`

横向滑动的ListView

 
阅读更多
http://www.eoeandroid.com/thread-211031-1-1.html
老外写的?

我通常把GridView设置成1行来代替横向的listview了,呵呵。
下面这个类留着以后试试。

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()){
                        int scrollx = mScroller.getCurrX();
                        mNextX = scrollx;
                }
                
                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();
        }
        
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
                boolean handled = super.dispatchTouchEvent(ev);
                handled |= mGesture.onTouchEvent(ev);
                return handled;
        }
        
        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) {
                        for(int i=0;i<getChildCount();i++){
                                View child = getChildAt(i);
                                if (isEventWithinView(e, child)) {
                                        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) {
                        int childCount = getChildCount();
                        for (int i = 0; i < childCount; i++) {
                                View child = getChildAt(i);
                                if (isEventWithinView(e, child)) {
                                        if (mOnItemLongClicked != null) {
                                                mOnItemLongClicked.onItemLongClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i));
                                        }
                                        break;
                                }

                        }
                }

                private boolean isEventWithinView(MotionEvent e, View child) {
            Rect viewRect = new Rect();
            int[] childPosition = new int[2];
            child.getLocationOnScreen(childPosition);
            int left = childPosition[0];
            int right = left + child.getWidth();
            int top = childPosition[1];
            int bottom = top + child.getHeight();
            viewRect.set(left, top, right, bottom);
            return viewRect.contains((int) e.getRawX(), (int) e.getRawY());
        }
        };

        

}


Android Horizontal ListView
http://www.dev-smart.com/archives/34
分享到:
评论
3 楼 zi413293813 2014-03-07  
gundumw100 写道
zi413293813 写道
楼主有没有发现一个问题,有时候会出现最后几条数据没显示的bug?!

这个类感觉不太好。我不用它!

有一个改进版了,用起来还OK
2 楼 gundumw100 2013-12-13  
zi413293813 写道
楼主有没有发现一个问题,有时候会出现最后几条数据没显示的bug?!

这个类感觉不太好。我不用它!
1 楼 zi413293813 2013-12-12  
楼主有没有发现一个问题,有时候会出现最后几条数据没显示的bug?!

相关推荐

    自定义横向滑动Listview 类

    然而,标准的ListView是垂直滚动的,有时我们可能需要实现一个横向滑动的列表效果,这在标题"自定义横向滑动Listview 类"中有所提及。这个自定义控件允许开发者创建一个可以左右滑动的列表,增加了用户体验的多样性...

    横向滑动ListView包括Demo

    标题提到的"横向滑动ListView包括Demo"是一个专门解决这一问题的项目,它提供了一个定制的解决方案,允许开发者创建水平滚动的列表。 这个项目由一位经验丰富的IT专家编写,包含了完整的源码和实际运行的示例,方便...

    横向滑动ListView

    然而,标准的ListView通常是垂直滚动的,而“横向滑动ListView”则是对这种组件的一种扩展,允许用户水平滑动来浏览列表项。这样的设计在展示横向数据流或者在有限的空间内展示更多内容时非常有用。 标题中的“横向...

    android横向滑动ListView

    横向滑动ListView,解决item onClick冲突

    图片视频横向滑动ListView

    【图片视频横向滑动ListView】是一种特殊的视图组件,它扩展了传统的Android ListView,使得在移动设备上可以水平滑动浏览一系列的图片和视频。在Android应用开发中,ListView通常用于垂直滚动显示列表数据,而...

    横向滑动listview 显示日期星期demo

    这个“横向滑动listview 显示日期星期demo”就是一个实现这种功能的例子。在这个项目中,开发者使用了HorizontalListView组件来替代传统的垂直滚动的ListView,以实现水平滑动的效果。 HorizontalListView是Android...

    实现可以横向滑动的Listview

    3. **使用第三方库**:有一些第三方库,如`androidx.recyclerview.widget.RecyclerView`(原生支持LinearLayoutManager的横向模式)或专门的HorizontalListView库(如`...,可以简化横向滑动ListView的实现...

    使用HorizonalScrollView实现ListView横向滑动

    在本教程中,我们将讨论如何结合`HorizontalScrollView`和`ListView`,实现一个可以水平滑动的列表视图。 首先,了解`HorizontalScrollView`的基本用法。`HorizontalScrollView`是一个单行布局,它只接受一个直接的...

    安卓listview相关相关-横向的listview可以左右滑动点击查看。.rar

    标题 "安卓listview相关相关-横向的listview可以左右滑动点击查看" 描述了一个在Android平台上实现的独特ListView,它不仅支持传统的垂直滚动,还具备横向滑动的功能,允许用户通过左右滑动来查看更多的内容。...

    安卓listview相关相关-HorizontalListViewDemo横向滑动的ListView.zip

    本示例"HorizontalListViewDemo"是一个专门针对横向滑动ListView的实现,它扩展了ListView的基本功能,允许用户在水平方向上浏览数据。 HorizontalListView的核心概念是将传统的垂直滚动转变为水平滚动,这在...

    在ListView中横向滑动的控件

    然而,标准的ListView只能实现垂直方向的滚动,如果你需要在一个ListView的每一项(Item)中添加横向滑动的功能,那么就需要对ListView进行扩展或者使用特殊的布局管理器来实现这种交互效果。这个“在ListView中横向...

    横向滑动的listView

    然而,标准的ListView默认是垂直滚动的,不支持横向滑动。在标题提到的"横向滑动的ListView"是一个自定义实现,允许用户水平浏览数据项,通常称为HorizontalListView或者RecyclerView的Horizontal模式。在本文中,...

    带固定列支持横向滑动的ListView

    带固定列支持横向滑动的ListView详解见http://blog.csdn.net/qiaohonglu/article/details/72571461

    android demo,自定义支持横向滚动的ListView。

    然而,标准的ListView默认只支持垂直滚动,对于需要横向展示数据的场景,开发者需要进行自定义实现。这个“android demo,自定义支持横向滚动的ListView”正是为了解决这个问题,让我们深入探讨相关知识点。 首先,...

    HorizontalListViewDemo 横向滑动的ListView

    HorizontalListViewDemo是一个专门为Android平台设计的示例项目,它展示了如何实现一个横向滑动的ListView。在Android原生系统中,ListView通常是垂直滚动的,但通过一些自定义控件或者第三方库,我们可以创建一个...

    Android横向列表,横向listview实现

    **三、实现横向滑动** 默认情况下,RecyclerView已经支持水平滑动,但为了增强用户体验,可以添加手势检测和滑动效果: 1. **添加滑动手势** 使用`GestureDetector`监听用户的滑动事件,可以添加平移和平滑滚动的...

    HorizontalListViewDemo 横向滑动的ListView 0分

    HorizontalListViewDemo是一个Android开发示例,它展示了如何创建一个可以横向滑动的ListView。在传统的Android开发中,ListView是常见的视图组件,用于显示一列可滚动的项目,但默认情况下,ListView仅支持竖向滚动...

Global site tag (gtag.js) - Google Analytics