天天看點

解決水準ListView在ScrollView中出現的滑動沖突

解決水準ListView在ScrollView中出現的滑動沖突

解決的問題有兩個: 

1)實作水準滑動的listview。重寫adapterview,上代碼: 

解決水準ListView在ScrollView中出現的滑動沖突

package com.liucanwen.horizontallistview.view;  

import java.util.linkedlist;  

import java.util.queue;  

import android.content.context;  

import android.database.datasetobserver;  

import android.graphics.rect;  

import android.util.attributeset;  

import android.view.gesturedetector;  

import android.view.gesturedetector.ongesturelistener;  

import android.view.view.measurespec;  

import android.view.motionevent;  

import android.view.view;  

import android.widget.adapterview;  

import android.widget.listadapter;  

import android.widget.scroller;  

/** 

 * 重寫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 + child.getpaddingright();  

            }  

        }  

    }  

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

        }  

    };  

}  

2)第一步實作了水準滑動,往往我們會把這個水準listview放到scrollview裡面(見截圖實作),而這兩個控件恰好滑動會有沖突,滑動水準listview時會有卡頓,是以重寫scrollview,以達到流暢滑動: 

解決水準ListView在ScrollView中出現的滑動沖突

package com.liucanwen.horizontallistview.view;  

import android.content.context;  

import android.util.attributeset;  

import android.view.gesturedetector;  

import android.view.gesturedetector.simpleongesturelistener;  

import android.view.motionevent;  

import android.view.view;  

import android.widget.scrollview;  

/** 

 * 重寫scrollview,以解決scrollview與水準listview滑動時沖突 

 */  

public class myscrollview extends scrollview  

{  

    private gesturedetector mgesturedetector;  

    view.ontouchlistener mgesturelistener;  

    public myscrollview(context context, attributeset attrs)  

    {  

        super(context, attrs);  

        mgesturedetector = new gesturedetector(new yscrolldetector());  

        setfadingedgelength(0);  

    }  

    @override  

    public boolean onintercepttouchevent(motionevent ev)  

    {  

        return super.onintercepttouchevent(ev)  

                && mgesturedetector.ontouchevent(ev);  

    }  

    class yscrolldetector extends simpleongesturelistener  

    {  

        @override  

        public boolean onscroll(motionevent e1, motionevent e2,  

                float distancex, float distancey)  

        {  

            if (math.abs(distancey) > math.abs(distancex))  

            {  

                return true;  

            }  

            return false;  

        }  

    }  

}  

好了,大功告成! 

以下系項目的源代碼下載下傳位址: 

<a target="_blank" href="http://download.csdn.net/detail/qq15989177612/6943633">http://download.csdn.net/detail/qq15989177612/6943633</a>