我正在尝试使圆形列表视图与列表项目排列在半圆上。它应该是这个样子:圆形列表视图(在半圆上的项目)
有一个related post但它被关闭。
我做了我自己的圆形自定义ListView,它工作正常,但我的问题是,我不能安排列表项目半圆方式,因为它显示在图像上。我尝试了几件事,但它没用,我不知道该怎么做。
我正在尝试使圆形列表视图与列表项目排列在半圆上。它应该是这个样子:圆形列表视图(在半圆上的项目)
有一个related post但它被关闭。
我做了我自己的圆形自定义ListView,它工作正常,但我的问题是,我不能安排列表项目半圆方式,因为它显示在图像上。我尝试了几件事,但它没用,我不知道该怎么做。
所以当我制作示例应用程序来演示这个时,我不得不做两件事。
首先,在我的自定义视图上编辑了onDraw(Canvas)
。这可以是任何视图,为了简单起见,我将它制作为TextView。这使我能够根据方程推送视图。
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;
}
}
我必须做的第二件事是要覆盖的ListView类,使其实现OnScrollListener并调用setOnScrollListener(this);
。现在我可以滚动浏览列表,它遵循我放入视图的等式。
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();
}
}
您可以从我的Gist下载完整的源代码。
初始状态 滚动状态
正如你可以看到我的数学是有点过......我用一个抛物线VS了一圈,这样就必须改变。
您可以为适配器的getView()中返回的每个视图增加/减少左边距。因此,例如,对于前半部分视图,您可以将每个项目的边距增加20像素(int margin = index * 20),并在后半部分视图中相应减小。
当然,这需要很多微调来真正看起来像一个循环列表,但我认为你明白了。
是的我已经试图这样做,但有一个问题。当适配器首先使用getView时,它会为一个项目创建一个视图,但之后它将使用之前使用过的视图的视图,并且您无法说出它将使用哪个视图,因此看起来很乱。 – Jilberta 2013-05-03 10:50:26
@Jilberta,问题有多大?每次执行该方法时,根据传递给getView()的位置设置边距。向我们显示您的代码,我们可能能够解决您的问题。 – TomTasche 2013-05-03 11:29:13
@Jilberta,你是对的,你从回收视图扩展的listview,如果以某些方式重用,他们可能会看起来“搞砸”,但请记住,你也可以设置一个http://developer.android.com/reference /android/widget/AbsListView.html#setRecyclerListener(android.widget.AbsListView.RecyclerListener)清除事件,如果他们造成混乱。最好。 – Tom 2013-05-04 17:22:13
我找到一个达到您想要 这里是什么哲github上来源 https://github.com/sam85/MySample/tree/master/CircleLauncher
经过一些更多护目镜,我找到了一个解决方案。
它是相对优化和可配置像一个正常的ListView。
这里是主要的代码片段:
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);
}
更多的澄清,你还可以看到我的博客文章,并在可以发表评论。您可以下载eclipse的示例应用程序。
我的博客是:
http://androidpantiii.blogspot.in/2015/11/half-circular-list-view-there-were.html
是什么让你觉得这是一个'ListView'? – CommonsWare 2013-05-02 00:33:24
这可能不是一个ListView,我只是有一个项目列表相当多,需要安排他们这样,但我不知道如何。 。 。没有必要成为一个ListView。 – Jilberta 2013-05-03 10:43:45
应该像ListView一样滚动吗? – 2013-05-04 11:38:12