synnapps studio discretescrollview discrete carrusel carouselview android android-layout carousel

discretescrollview - image slider android studio



¿Cómo crear una página desplazable de carruseles en Android? (6)

Idea principal

Para tener un diseño flexible y tener elementos ilimitados , puede crear un RecyclerView como vista de raíz con LinearLayoutManager.VERTICAL como LayoutManager . para cada fila puede poner otra RecyclerView pero ahora con LinearLayoutManager.HORIZONTAL como LayoutManager .

Resultado

Fuente

Code

Requisitos

1) El desplazamiento vertical entre carruseles debe ser uniforme, pero cuando el usuario lo suelta, la IU debe "ajustarse" al carrusel más cercano (para que el usuario esté siempre en una fila de carrusel, no entre dos carruseles).

2) El desplazamiento horizontal en un carrusel debe ser uniforme, pero cuando el usuario lo suelta, la IU debe "ajustarse" al elemento más cercano en el carrusel.

Para lograr ésos utilicé OnScrollListener y cuando los estados van SCROLL_STATE_IDLE miro las vistas superior e inferior para ver cuál de ellas tiene una región más visible y luego me desplazo a esa posición. para cada fila, lo hago para las vistas izquierda y derecha de cada adaptador de fila. De esta forma, siempre quedará un lado de tus carruseles o filas. por ejemplo, si la parte superior está ajustada, la parte inferior no es o viceversa. Creo que si juegas un poco más puedes lograr eso, pero debes conocer la dimensión de la ventana y cambiar la dimensión de los carruseles en tiempo de ejecución.

3) Debería ser posible superponer información adicional sobre un elemento en el carrusel

Si utiliza RelativeLayout o FrameLayout como una vista de raíz de cada elemento, puede poner información uno encima del otro. como puede ver, los números están en la parte superior de las imágenes.

4) La interfaz de usuario debe ser adaptable a cualquier tamaño de pantalla.

si sabe cómo admitir el tamaño de pantalla múltiple puede hacerlo fácilmente, si no sabe leer el documento. Compatible con pantallas múltiples

5) Debe ser navegable con las teclas de flecha (para dispositivos sin pantalla táctil)

usar debajo de la función

mRecyclerView.scrollToPosition(position);

6) Debería funcionar en una amplia gama de versiones de Android (posiblemente a través de la biblioteca de soporte)

Importar Android. support.v7 .widget.RecyclerView;

7) Debe estar bien para usar en una aplicación de código abierto con licencia bajo la GPL

De acuerdo

feliz codificación !!

Estoy intentando construir una interfaz de usuario para mi aplicación de Android que contiene una página verticalmente desplazable de carruseles desplazables horizontalmente (algo así como lo que hace la aplicación Netflix). ¿Cómo se logra este tipo de comportamiento?

Una implementación básica sería suficiente para comenzar. Existen algunos otros requisitos para la IU, que incluiré aquí como referencia, ya que pueden afectar las clases o bibliotecas que puedo usar.

1) El desplazamiento vertical entre carruseles debe ser uniforme, pero cuando el usuario lo suelta, la IU debe "ajustarse" al carrusel más cercano (para que el usuario esté siempre en una fila de carrusel, no entre dos carruseles).

2) El desplazamiento horizontal en un carrusel debe ser uniforme, pero cuando el usuario lo suelta, la IU debe "ajustarse" al elemento más cercano en el carrusel.

3) Debería ser posible superponer información adicional sobre un elemento en el carrusel

4) La interfaz de usuario debe ser adaptable a cualquier tamaño de pantalla.

5) Debe ser navegable con las teclas de flecha (para dispositivos sin pantalla táctil)

6) Debería funcionar en una amplia gama de versiones de Android (posiblemente a través de la biblioteca de soporte)

7) Debe estar bien para usar en una aplicación de código abierto con licencia bajo la GPL

Las respuestas aceptables NO tienen que cumplir con todos estos requisitos. Como mínimo, una buena respuesta debería involucrar la navegación de carruseles múltiples (frente a un solo carrusel).

Aquí hay una maqueta de básicamente lo que estoy visualizando (soy flexible, no tiene que parecerse a esto ... el punto es solo aclarar a qué me refiero; cada fila contendría una gran cantidad de elementos que podrían desplazarse hacia la izquierda y hacia la derecha, y toda la página se puede desplazar hacia arriba y hacia abajo)


Hace un tiempo necesitaba algo así, acabo de usar eso: https://github.com/simonrob/Android-Horizontal-ListView

Simple, poderoso, personalizable.

Ejemplo de mi versión:

public class HorizontalListView extends AdapterView<ListAdapter> { public boolean mAlwaysOverrideTouch = true; protected ListAdapter mAdapter; private int mLeftViewIndex = -1; private int mRightViewIndex = 0; protected int mCurrentX; protected int mNextX; private int mMaxX = Integer.MAX_VALUE; private int mDisplayOffset = 0; protected Scroller mScroller; private GestureDetector mGesture; private Queue<View> mRemovedViewQueue = new LinkedList<View>(); private OnItemSelectedListener mOnItemSelected; private OnItemClickListener mOnItemClicked; private OnItemLongClickListener mOnItemLongClicked; private boolean mDataChanged = false; public HorizontalListView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private synchronized void initView() { mLeftViewIndex = -1; mRightViewIndex = 0; mDisplayOffset = 0; mCurrentX = 0; mNextX = 0; mMaxX = Integer.MAX_VALUE; mScroller = new Scroller(getContext()); mGesture = new GestureDetector(getContext(), mOnGesture); } @Override public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) { mOnItemSelected = listener; } @Override public void setOnItemClickListener(AdapterView.OnItemClickListener listener) { mOnItemClicked = listener; } @Override public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) { mOnItemLongClicked = listener; } private DataSetObserver mDataObserver = new DataSetObserver() { @Override public void onChanged() { synchronized (HorizontalListView.this) { mDataChanged = true; } invalidate(); requestLayout(); } @Override public void onInvalidated() { reset(); invalidate(); requestLayout(); } }; @Override public ListAdapter getAdapter() { return mAdapter; } @Override public View getSelectedView() { //TODO: implement return null; } @Override public void setAdapter(ListAdapter adapter) { if (mAdapter != null) { mAdapter.unregisterDataSetObserver(mDataObserver); } mAdapter = adapter; mAdapter.registerDataSetObserver(mDataObserver); reset(); } private synchronized void reset() { initView(); removeAllViewsInLayout(); requestLayout(); } @Override public void setSelection(int position) { //TODO: implement } private void addAndMeasureChild(final View child, int viewPos) { LayoutParams params = child.getLayoutParams(); if (params == null) { params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); } addViewInLayout(child, viewPos, params, true); child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); } @Override protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (mAdapter == null) { return; } if (mDataChanged) { int oldCurrentX = mCurrentX; initView(); removeAllViewsInLayout(); mNextX = oldCurrentX; mDataChanged = false; } if (mScroller.computeScrollOffset()) { mNextX = mScroller.getCurrX(); } if (mNextX <= 0) { mNextX = 0; mScroller.forceFinished(true); } if (mNextX >= mMaxX) { mNextX = mMaxX; mScroller.forceFinished(true); } int dx = mCurrentX - mNextX; removeNonVisibleItems(dx); fillList(dx); positionItems(dx); mCurrentX = mNextX; if (!mScroller.isFinished()) { post(new Runnable() { @Override public void run() { requestLayout(); } }); } } private void fillList(final int dx) { int edge = 0; View child = getChildAt(getChildCount() - 1); if (child != null) { edge = child.getRight(); } fillListRight(edge, dx); edge = 0; child = getChildAt(0); if (child != null) { edge = child.getLeft(); } fillListLeft(edge, dx); } private void fillListRight(int rightEdge, final int dx) { while (rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) { View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this); addAndMeasureChild(child, -1); rightEdge += child.getMeasuredWidth(); if (mRightViewIndex == mAdapter.getCount() - 1) { mMaxX = mCurrentX + rightEdge - getWidth(); } if (mMaxX < 0) { mMaxX = 0; } mRightViewIndex++; } } private void fillListLeft(int leftEdge, final int dx) { while (leftEdge + dx > 0 && mLeftViewIndex >= 0) { View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this); addAndMeasureChild(child, 0); leftEdge -= child.getMeasuredWidth(); mLeftViewIndex--; mDisplayOffset -= child.getMeasuredWidth(); } } private void removeNonVisibleItems(final int dx) { View child = getChildAt(0); while (child != null && child.getRight() + dx <= 0) { mDisplayOffset += child.getMeasuredWidth(); mRemovedViewQueue.offer(child); removeViewInLayout(child); mLeftViewIndex++; child = getChildAt(0); } child = getChildAt(getChildCount() - 1); while (child != null && child.getLeft() + dx >= getWidth()) { mRemovedViewQueue.offer(child); removeViewInLayout(child); mRightViewIndex--; child = getChildAt(getChildCount() - 1); } } private void positionItems(final int dx) { if (getChildCount() > 0) { mDisplayOffset += dx; int left = mDisplayOffset; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int childWidth = child.getMeasuredWidth(); child.layout(left, 0, left + childWidth, child.getMeasuredHeight()); left += childWidth; } } } public synchronized void scrollTo(int x) { mScroller.startScroll(mNextX, 0, x - mNextX, 0); requestLayout(); } public synchronized void scrollToChild(int position) { //TODO requestLayout(); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return mGesture.onTouchEvent(ev); } protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { synchronized (HorizontalListView.this) { mScroller.fling(mNextX, 0, (int) -velocityX, 0, 0, mMaxX, 0, 0); } requestLayout(); return true; } protected boolean onDown(MotionEvent e) { mScroller.forceFinished(true); return true; } private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { return HorizontalListView.this.onDown(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { synchronized (HorizontalListView.this) { mNextX += (int) distanceX; } requestLayout(); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { Rect viewRect = new Rect(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int left = child.getLeft(); int right = child.getRight(); int top = child.getTop(); int bottom = child.getBottom(); viewRect.set(left, top, right, bottom); if (viewRect.contains((int) e.getX(), (int) e.getY())) { if (mOnItemClicked != null) { mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); } if (mOnItemSelected != null) { mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); } break; } } return true; } @Override public void onLongPress(MotionEvent e) { Rect viewRect = new Rect(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); int left = child.getLeft(); int right = child.getRight(); int top = child.getTop(); int bottom = child.getBottom(); viewRect.set(left, top, right, bottom); if (viewRect.contains((int) e.getX(), (int) e.getY())) { if (mOnItemLongClicked != null) { mOnItemLongClicked.onItemLongClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); } break; } } } }; }

Aquí está el XML:

<com.example.package.widgets.HorizontalListView android:id="@+id/horizontal_listview" android:layout_marginTop="30dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_width="fill_parent" android:layout_height="80dp" android:background="@color/light_gray" />

En el OnCreate:

mAdapter = new ArrayAdapter<Uri>(this, R.layout.viewitem) { @Override public int getCount() { return listUriAdapter.size(); } @Override public Uri getItem(int position) { return listUriAdapter.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { // do what you have to do return retval; } }; onItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { } }; onItemLongClickListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { return false; } }; horizontalListView.setOnItemClickListener(onItemClickListener); horizontalListView.setOnItemLongClickListener(onItemLongClickListener); horizontalListView.setAdapter(mAdapter);


Prueba ViewPager. This es la documentación.


Puede usar ListView con un OnTouchListener personalizado (para ajustar elementos) para el desplazamiento vertical y TwoWayGridView nuevamente con un OnTouchListener personalizado (para ajustar elementos)

main.xml

<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/containerList" android:layout_width="match_parent" android:layout_height="300dp" android:background="#E8E8E8" android:divider="@android:color/transparent" android:dividerHeight="16dp" />

list_item_hgrid.xml

<com.jess.ui.TwoWayGridView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="160dp" android:layout_marginBottom="16dp" app:cacheColorHint="#E8E8E8" app:columnWidth="128dp" app:gravity="center" app:horizontalSpacing="16dp" app:numColumns="auto_fit" app:numRows="1" app:rowHeight="128dp" app:scrollDirectionLandscape="horizontal" app:scrollDirectionPortrait="horizontal" app:stretchMode="spacingWidthUniform" app:verticalSpacing="16dp" />

Y el código de actividad será algo así como el siguiente

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test); ListView containerList = (ListView) findViewById(R.id.containerList); containerList.setAdapter(new DummyGridsAdapter(this)); containerList.setOnTouchListener(mContainerListOnTouchListener); } private View.OnTouchListener mContainerListOnTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: View itemView = ((ListView) view).getChildAt(0); int top = itemView.getTop(); if (Math.abs(top) >= itemView.getHeight() / 2) { top = itemView.getHeight() - Math.abs(top); } ((ListView) view).smoothScrollBy(top, 400); } return false; } };

Y aquí están los adaptadores de prueba

private static class DummyGridsAdapter extends BaseAdapter { private Context mContext; private TwoWayGridView[] mChildGrid; public DummyGridsAdapter(Context context) { mContext = context; mChildGrid = new TwoWayGridView[getCount()]; for (int i = 0; i < mChildGrid.length; i++) { mChildGrid[i] = (TwoWayGridView) LayoutInflater.from(context). inflate(R.layout.list_item_hgrid, null); mChildGrid[i].setAdapter(new DummyImageAdapter(context)); mChildGrid[i].setOnTouchListener(mChildGridOnTouchListener); } } @Override public int getCount() { return 8; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { return mChildGrid[position]; } private View.OnTouchListener mChildGridOnTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: View itemView = ((TwoWayGridView) view).getChildAt(0); int left = itemView.getLeft(); if (Math.abs(left) >= itemView.getWidth() / 2) { left = itemView.getWidth() - Math.abs(left); } ((TwoWayGridView) view).smoothScrollBy(left, 400); } return false; } }; } private static class DummyImageAdapter extends BaseAdapter { private Context mContext; private final int mDummyViewWidthHeight; public DummyImageAdapter(Context context) { mContext = context; mDummyViewWidthHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 128, context.getResources().getDisplayMetrics()); } @Override public int getCount() { return 16; } @Override public Object getItem(int position) { int component = (getCount() - position - 1) * 255 / getCount(); return Color.argb(255, 255, component, component); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(mContext); imageView.setBackgroundColor((Integer) getItem(position)); imageView.setLayoutParams(new TwoWayGridView.LayoutParams(mDummyViewWidthHeight, mDummyViewWidthHeight)); return imageView; } }



Sugeriría la vista de Recycler.

Puede crear listas horizontales y verticales o vistas de cuadrícula. En mi opinión, el viewpager puede complicarse a veces.

Estoy trabajando en la aplicación de video a pedido y esto me salvó.

En tu caso, será fácil de configurar. Te daré un código.

Necesitarás lo siguiente:
Vista XML: donde se declara el diseño de reciclaje.
Adaptador: necesitará una vista para completar el adaptador y completar la vista de reciclaje.

Creando la vista

<android.support.v7.widget.RecyclerView android:id="@+id/recycle_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" android:orientation="horizontal" android:gravity="center" android:overScrollMode="never"/>

Declare esto donde desea que se muestre el carrusel.

A continuación, quiere crear el adaptador:

public class HorizontalCarouselItemAdapter extends RecyclerView.Adapter<HorizontalCarouselItemAdapter.ViewHolder> { List<objects> items; int itemLayout; public HorizontalCarouselItemAdapter(Context context, int itemLayout, List<objects> items) { this.context = context; this.itemLayout = itemLayout; this.items = items; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(final ViewHolder holder, final int position) { this.holders = holder; final GenericAsset itemAdapter = items.get(position); holder.itemImage.setDrawable //manipulate variables here } @Override public int getItemCount() { return items.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView itemImage; public ViewHolder(View itemView) { super(itemView); itemImage = (ImageView) itemView.findViewById(R.id.carousel_cell_holder_image); } }

Aquí es donde usted alimenta los datos al adaptador para llenar cada elemento del carrusel.
Finalmente declararlo y llamar al adaptador:

recyclerView = (RecyclerView)findViewById(R.id.recycle_view); ListLayoutManager manager = new ListLayoutManager(getApplication(), ListLayoutManager.Orientation.HORIZONTAL); recyclerView.setLayoutManager(manager); CustomAdpater adapter = new CustomAdapter(getApplication(), data); recyclerView.setAdapter(adapter);

Puede crear una vista de lista con vistas de reciclaje para lograr lo que desea.
Esta clase es ideal para el desplazamiento suave y la optimización de la memoria.

Este es el enlace para ello:

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html

Espero que esto te ayude.