`

横向滑动的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?!

相关推荐

Global site tag (gtag.js) - Google Analytics