ListView circular (elementos en el medio círculo)

Estoy tratando de hacer un ListView circular con elementos de lista dispuestos en medio círculo. Debe verse algo como esto:

Introduzca aquí la descripción de la imagen

Había un post relacionado pero estaba cerrado.

Hice mi propio ListView personalizado circular y funciona bien, pero mi problema es que no puedo arreglar los elementos de lista de medio círculo como se muestra en la imagen. Intenté varias cosas pero fue inútil, no sé cómo hacerlo.

Así que cuando hice la aplicación de ejemplo para demostración de esto tuve que hacer 2 cosas.

En primer lugar, editar el onDraw(Canvas) en mi vista personalizada. Esto podría ser cualquier vista, lo hago un TextView para la simplicidad. Esto me permite empujar la vista sobre la base de una ecuación.

 public class MyView extends TextView { private static final int MAX_INDENT = 300; private static final String TAG = MyView.class.getSimpleName(); public MyView(Context context) { super(context); } public void onDraw(Canvas canvas){ canvas.save(); float indent = getIndent(getY()); canvas.translate(indent, 0); super.onDraw(canvas); canvas.restore(); } public float getIndent(float distance){ float x_vertex = MAX_INDENT; DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); float y_vertex = displayMetrics.heightPixels / 2 / displayMetrics.density; double a = ( 0 - x_vertex ) / ( Math.pow(( 0 - y_vertex), 2) ) ; float indent = (float) (a * Math.pow((distance - y_vertex), 2) + x_vertex); return indent; } } 

La segunda cosa que tenía que hacer era sobreescribir la clase ListView, hacerla implementar OnScrollListener y llamar a setOnScrollListener(this); . Ahora puedo desplazarme por la lista, sigue la ecuación que pongo en la vista.

 public class HalfCircleListView extends ListView implements AbsListView.OnScrollListener { public HalfCircleListView(Context context) { super(context); setOnScrollListener(this); } @Override public void onScrollStateChanged(AbsListView absListView, int i) { //Ignored } @Override public void onScroll(AbsListView absListView, int i, int i2, int i3) { absListView.invalidateViews(); } } 

Puedes descargar la fuente completa de mi Gist .

Estado inicial Estado inicial de la vista Estado desplazado Desplazado hacia abajo

Como se puede ver mi matemáticas es un poco fuera … Yo uso una parábola vs un círculo, por lo que tendrá que ser cambiado.

Puede aumentar / disminuir el margen izquierdo para cada vista devuelta en su adaptador getView (). Así, por ejemplo, para la primera mitad de sus puntos de vista, aumenta el margen de cada elemento, por ejemplo, 20 píxeles (int margin = index * 20), y disminuya en consecuencia para la segunda mitad de las vistas.

Esto necesita una gran cantidad de ajuste fino para realmente parece una lista circular, por supuesto, pero creo que tienes la idea.

Intentaría usar un widget de menú radial existente si es posible. Éste pretende apoyar un menú radial semicircular. No estoy seguro de si este hace o no.

Puede ser esto le ayudará,

Mira aquí

Mira esto

Espero que esto te ayudará 🙂

I encontrar un lograr lo que quieres y aquí es zhe github fuente https://github.com/sam85/MySample/tree/master/CircleLauncher

Después de algunos más goggling, encontré una solución.
Es relativamente optimizado y configurable como un ListView normal.

Aquí hay fragmentos de código principal:

CircularListView.java

 package com.makotokw.android.widget; import android.annotation.TargetApi; import android.content.Context; import android.database.DataSetObserver; import android.os.Build; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.ListAdapter; import android.widget.ListView; public class CircularListView extends ListView implements AbsListView.OnScrollListener { private static final String TAG = CircularListView.class.getSimpleName(); private static final int REPEAT_COUNT = 3; private int mItemHeight = 0; private CircularListViewListener mCircularListViewListener; private InfiniteListAdapter mInfiniteListAdapter; private boolean mEnableInfiniteScrolling = true; private CircularListViewContentAlignment mCircularListViewContentAlignment = CircularListViewContentAlignment.Left; private double mRadius = -1; private int mSmoothScrollDuration = 80; public CircularListView(Context context) { this(context, null); } public CircularListView(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.listViewStyle); } public CircularListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setOnScrollListener(this); setClipChildren(false); setEnableInfiniteScrolling(true); } public void setAdapter(ListAdapter adapter) { mInfiniteListAdapter = new InfiniteListAdapter(adapter); mInfiniteListAdapter.setEnableInfiniteScrolling(mEnableInfiniteScrolling); super.setAdapter(mInfiniteListAdapter); } public CircularListViewListener getCircularListViewListener() { return mCircularListViewListener; } public void setCircularListViewListener(CircularListViewListener circularListViewListener) { this.mCircularListViewListener = circularListViewListener; } public void setEnableInfiniteScrolling(boolean enableInfiniteScrolling) { mEnableInfiniteScrolling = enableInfiniteScrolling; if (mInfiniteListAdapter != null) { mInfiniteListAdapter.setEnableInfiniteScrolling(enableInfiniteScrolling); } if (mEnableInfiniteScrolling) { setHorizontalScrollBarEnabled(false); setVerticalScrollBarEnabled(false); } } public CircularListViewContentAlignment getCircularListViewContentAlignment() { return mCircularListViewContentAlignment; } public void setCircularListViewContentAlignment( CircularListViewContentAlignment circularListViewContentAlignment) { if (mCircularListViewContentAlignment != circularListViewContentAlignment) { mCircularListViewContentAlignment = circularListViewContentAlignment; requestLayout(); } } public double getRadius() { return mRadius; } public void setRadius(double radius) { if (this.mRadius != radius) { this.mRadius = radius; requestLayout(); } } public int getCentralPosition() { double vCenterPos = getHeight() / 2.0f; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child != null) { if (child.getTop() <= vCenterPos && child.getTop() + child.getHeight() >= vCenterPos) { return getFirstVisiblePosition() + i; } } } return -1; } public View getCentralChild() { int pos = getCentralPosition(); if (pos != -1) { return getChildAt(pos - getFirstVisiblePosition()); } return null; } public void scrollFirstItemToCenter() { if (!mEnableInfiniteScrolling) { return; } int realTotalItemCount = mInfiniteListAdapter.getRealCount(); if (realTotalItemCount > 0) { setSelectionFromTop(realTotalItemCount, getBaseCentralChildTop()); } } public int getBaseCentralChildTop() { int itemHeight = getItemHeight(); if (itemHeight > 0) { return getHeight() / 2 - itemHeight / 2; } return 0; } public int getItemHeight() { if (mItemHeight == 0) { View child = getChildAt(0); if (child != null) { mItemHeight = child.getHeight(); } } return mItemHeight; } public void setSelectionAndMoveToCenter(int position) { if (!mEnableInfiniteScrolling) { return; } int realTotalItemCount = mInfiniteListAdapter.getRealCount(); if (realTotalItemCount == 0) { return; } position = position % realTotalItemCount; int centralPosition = getCentralPosition() % realTotalItemCount; int y = getBaseCentralChildTop(); if (centralPosition == position) { View centralView = getCentralChild(); y = centralView.getTop(); } setSelectionFromTop(position + realTotalItemCount, y); } @TargetApi(Build.VERSION_CODES.FROYO) @Override public boolean dispatchKeyEvent(KeyEvent event) { if (mEnableInfiniteScrolling) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_UP: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { smoothScrollBy(mItemHeight, mSmoothScrollDuration); return true; } break; case KeyEvent.KEYCODE_DPAD_DOWN: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { smoothScrollBy(-mItemHeight, mSmoothScrollDuration); return true; } break; default: break; } } } return super.dispatchKeyEvent(event); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == SCROLL_STATE_IDLE) { if (!isInTouchMode()) { setSelectionAndMoveToCenter(getCentralPosition()); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (!mEnableInfiniteScrolling) { return; } View itemView = this.getChildAt(0); if (itemView == null) { return; } int realTotalItemCount = mInfiniteListAdapter.getRealCount(); if (realTotalItemCount == 0) { return; } if (mItemHeight == 0) { mItemHeight = itemView.getHeight(); } if (firstVisibleItem == 0) { // scroll one unit this.setSelectionFromTop(realTotalItemCount, itemView.getTop()); } if (totalItemCount == firstVisibleItem + visibleItemCount) { // back one unit this.setSelectionFromTop(firstVisibleItem - realTotalItemCount, itemView.getTop()); } if (mCircularListViewContentAlignment != CircularListViewContentAlignment.None) { double viewHalfHeight = view.getHeight() / 2.0f; double vRadius = view.getHeight(); double hRadius = view.getWidth(); double yRadius = (view.getHeight() + mItemHeight) / 2.0f; double xRadius = (vRadius < hRadius) ? vRadius : hRadius; if (mRadius > 0) { xRadius = mRadius; } for (int i = 0; i < visibleItemCount; i++) { itemView = this.getChildAt(i); if (itemView != null) { double y = Math.abs(viewHalfHeight - (itemView.getTop() + (itemView.getHeight() / 2.0f))); y = Math.min(y, yRadius); double angle = Math.asin(y / yRadius); double x = xRadius * Math.cos(angle); if (mCircularListViewContentAlignment == CircularListViewContentAlignment.Left) { x -= xRadius; } else { x = xRadius / 2 - x; } itemView.scrollTo((int) x, 0); } } } else { for (int i = 0; i < visibleItemCount; i++) { itemView = this.getChildAt(i); if (itemView != null) { itemView.scrollTo(0, 0); } } } if (mCircularListViewListener != null) { mCircularListViewListener.onCircularLayoutFinished(this, firstVisibleItem, visibleItemCount, totalItemCount); } } class InfiniteListAdapter implements ListAdapter { private boolean mEnableInfiniteScrolling = true; private ListAdapter mCoreAdapter; public InfiniteListAdapter(ListAdapter coreAdapter) { mCoreAdapter = coreAdapter; } private void setEnableInfiniteScrolling(boolean enableInfiniteScrolling) { mEnableInfiniteScrolling = enableInfiniteScrolling; } public int getRealCount() { return mCoreAdapter.getCount(); } public int positionToIndex(int position) { int count = mCoreAdapter.getCount(); return (count == 0) ? 0 : position % count; } @Override public void registerDataSetObserver(DataSetObserver observer) { mCoreAdapter.registerDataSetObserver(observer); } @Override public void unregisterDataSetObserver(DataSetObserver observer) { mCoreAdapter.unregisterDataSetObserver(observer); } @Override public int getCount() { int count = mCoreAdapter.getCount(); return (mEnableInfiniteScrolling) ? count * REPEAT_COUNT : count; } @Override public Object getItem(int position) { return mCoreAdapter.getItem(this.positionToIndex(position)); } @Override public long getItemId(int position) { return mCoreAdapter.getItemId(this.positionToIndex(position)); } @Override public boolean hasStableIds() { return mCoreAdapter.hasStableIds(); } @Override public View getView(int position, View convertView, ViewGroup parent) { return mCoreAdapter.getView(this.positionToIndex(position), convertView, parent); } @Override public int getItemViewType(int position) { return mCoreAdapter.getItemViewType(this.positionToIndex(position)); } @Override public int getViewTypeCount() { return mCoreAdapter.getViewTypeCount(); } @Override public boolean isEmpty() { return mCoreAdapter.isEmpty(); } @Override public boolean areAllItemsEnabled() { return mCoreAdapter.areAllItemsEnabled(); } @Override public boolean isEnabled(int position) { return mCoreAdapter.isEnabled(this.positionToIndex(position)); } } } **CircularListViewContentAlignment.java** package com.makotokw.android.widget; public enum CircularListViewContentAlignment { None, Left, Right } **CircularListViewListener.java** package com.makotokw.android.widget; public interface CircularListViewListener { void onCircularLayoutFinished(CircularListView circularListView, int firstVisibleItem, int visibleItemCount, int totalItemCount); } 

Para más aclaraciones, también puedes ver mi entrada en el blog y comentar sobre eso. Puede descargar la aplicación de ejemplo para eclipse.
Mi blog es:
http://androidpantiii.blogspot.in/2015/11/half-circular-list-view-there-were.html

  • Añadir elementos a ListView - Android
  • Mantenga un valor EditText en un ListView
  • ListView.getCheckedItemPositions no puede devolver elementos marcados en SparseBooleanArray
  • Android - autoLink
  • Gran número de TextViews un éxito de rendimiento? ¿Debo cambiar a ListView en lugar de usar Scrollview?
  • RealmBaseAdapter con encabezados de sección
  • Android: ¿Obtener la altura del elemento ListView?
  • Listview no actualizar en fragmento con las pestañas viewpager
  • Android listview mensaje vacío con encabezado
  • ListView con los botones y la matriz estática de la secuencia
  • Cómo deshabilitar el menú contextual para determinados elementos ListView en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.