Come creare una pagina scorrevole di caroselli in Android?

Sto tentando di creare un interface utente per la mia applicazione Android che contiene una pagina verticale scorrevole di caroselli scorrevoli orizzontalmente (qualcosa di simile a quello che fa l'applicazione Netflix). Come si compie questo tipo di comportmento?

Una implementazione di base sarebbe sufficiente per farti iniziare. Esistono alcuni altri requisiti per l'interface utente, che includo qui per riferimento, in quanto potrebbe influenzare le classi o le librerie che posso utilizzare.

  • Come faccio ad utilizzare un disegno composto anziché un LinearLayout che contiene un ImageView e un TextView
  • La canvas non viene disegnata nella visualizzazione personalizzata
  • Android: frammento non può get attività
  • Errore di Mac Creazione di un progetto Android - "Errori che eseguono il generatore di risorse Android Resource Manager" sul progetto "
  • Mostra l'image di formato Tiff in Android
  • Imansible capire NullPointerException con la scheda personalizzata
  • 1) Lo scorrimento verticale tra i caroselli dovrebbe essere liscia, ma quando l'utente rilascia, l'UI dovrà "scattare" il carosello più vicino (quindi l'utente è sempre su una row di carosello, non tra due caroselli).

    2) Lo scorrimento orizzontale su una giostra dovrebbe essere liscia, ma quando l'utente rilascia, l'UI dovrebbe "scattare" l'elemento più vicino nella giostra.

    3) Dovrebbe essere ansible sovrapporre informazioni aggiuntive su un elemento nella giostra

    4) L'interface utente deve essere adattabile a qualsiasi dimensione dello schermo.

    5) Dovrebbe essere navigabile con le frecce (per i dispositivi senza tattile)

    6) Dovrebbe lavorare su una vasta gamma di versioni Android (possibilmente attraverso la libreria di supporto)

    7) Dovrebbe essere OK per utilizzare in un'applicazione open source concessa in licenza sotto la GPL

    Risposte accettabili NON devono soddisfare tutti questi requisiti. Al minimo, una buona risposta dovrebbe implicare la navigazione di più caroselli (rispetto a un solo giostra).

    Ecco un model di sostanzialmente quello che sto immaginando (io sono flessibile, non devo assomigliare a questo … il punto è solo quello di chiarire ciò che sto parlando – each row contenere un sacco di elementi che potrebbero scorrere a sinistra ea destra, e l'intera pagina potrebbe essere scrollata su e giù)

    immettere qui la descrizione dell'immagine

  • Supporto multiscreen Android in android: 540x960 issue
  • android Maps API v2 con marcatori personalizzati
  • Android Bluetooth - Imansible connettersi
  • Imansible impostare un elemento del sottomenu come selezionato
  • Utilizzo di In Dependency Injection con Roboguice?
  • Tastiera rigida Imansible concentrarsi su editText
  • 6 Solutions collect form web for “Come creare una pagina scorrevole di caroselli in Android?”

    Idea principale

    Per avere un design flessibile e avere elementi illimitati è ansible creare un RecyclerView come una vista di origine con un LinearLayoutManager.VERTICAL come LayoutManager . per each row è ansible inserire un altro RecyclerView ma ora con LinearLayoutManager.HORIZONTAL come LayoutManager .

    Risultato

    immettere qui la descrizione dell'immagine

    fonte

    Codice

    Requisiti

    1) Lo scorrimento verticale tra i caroselli dovrebbe essere liscia, ma quando l'utente rilascia, l'UI dovrà "scattare" il carosello più vicino (quindi l'utente è sempre su una row di carosello, non tra due caroselli).

    2) Lo scorrimento orizzontale su una giostra dovrebbe essere liscia, ma quando l'utente rilascia, l'UI dovrebbe "scattare" l'elemento più vicino nella giostra.

    Per get quelli che ho usato OnScrollListener e quando gli stati va SCROLL_STATE_IDLE controlla le viste in alto e in basso per vedere quale di esse ha regione più visibile e scorrere fino a quella posizione. per each righe lo faccio per le visualizzazioni sinistro e destro per each adattatore di row. In questo modo sempre un lato dei vostri caroselli o righe si adattano. per esempio se la parte superiore è montata il fondo non è o viceversa. Penso che se si gioca un po 'più si può raggiungere questo objective, ma è necessario conoscere la dimensione della window e cambiare la dimensione dei caroselli in fase di runtime.

    3) Dovrebbe essere ansible sovrapporre informazioni aggiuntive su un elemento nella giostra

    Se si utilizza RelativeLayout o FrameLayout come una vista di origine di each elemento, è ansible mettere le informazioni in cima all'altro. come si può vedere i numbers sono in cima alle immagini.

    4) L'interface utente deve essere adattabile a qualsiasi dimensione dello schermo.

    se sai come supportre più size dello schermo, puoi farlo facilmente se non sai leggere il documento. Supporto di più schermate

    5) Dovrebbe essere navigabile con le frecce (per i dispositivi senza tattile)

    utilizzare sotto la function

     mRecyclerView.scrollToPosition(position); 

    6) Dovrebbe lavorare su una vasta gamma di versioni Android (possibilmente attraverso la libreria di supporto)

    importzione android. support.v7 .widget.RecyclerView;

    7) Dovrebbe essere OK per utilizzare in un'applicazione open source concessa in licenza sotto la GPL

    Ok

    codifica felice !!

    È ansible utilizzare ListView con un OnTouchListener personalizzato (per gli elementi di scatto) per lo scorrimento verticale e TwoWayGridView nuovamente con un OnTouchListener personalizzato (per gli elementi di scatto)

    immettere qui la descrizione dell'immagine

    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" /> 

    Il codice Activity sarà qualcosa di simile al seguito

     @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; } }; 

    Ecco gli adattatori di prova

     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; } } 

    Provate ViewPager. Questa è la documentazione.

    Vorrei suggerire la vista Recycler.

    È ansible creare liste orizzontali e verticali o gridviews. A mio parere, il viewpager può diventare complicato a volte.

    Sto lavorando all'applicazione video su richiesta e questo mi ha salvato.

    Nel tuo caso sarà facile da installare. Ti darò un codice.

    Avnetworking bisogno di:
    Visualizzazione XML – Dove viene dichiarato il layout del riciclo.
    Adattatore – Avnetworking bisogno di una vista per popolare l'adattatore e riempire il riciclaggio.

    Creazione della 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"/> 

    Dichiarare questo where vuoi che venga visualizzato il carosello.

    Avanti si desidera creare l'adattatore:

     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); } } 

    Questo è where i dati vengono alimentati all'adattatore per popolare each elemento carosello.
    Infine dichiararla e call l'adattatore:

     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); 

    Puoi creare una listview con le visualizzazioni di riciclo per get quello che vuoi.
    Questa class è ottima per lo scorrimento regolare e l'ottimizzazione della memory.

    Questo è il collegamento per esso:

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

    Spero che questo ti aiuta.

    È ansible utilizzare uno ScrollView come genitore all'interno di ScrollView che ScrollView un Vertical LinearLayout in for loop gonfiare un layout che consiste di coverflow per l' effetto carosello

    • github link di android-coverflow

    Avevo bisogno di qualcosa di simile a un po 'indietro, ho usato solo che: https://github.com/simonrob/Android-Horizontal-ListView

    Semplice, potente, personalizzabile.

    Esempio della mia versione:

     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; } } } }; } 

    Ecco l'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" /> 

    In 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); 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.