![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuMDMmJzY0MmMkdTNz0CZjJmYtQmZjNTLmRmZ20CO5IGOjJWMx8CXwcTNw8CX0kDMw8CX05WZth2YhRHdh9CXkF2bsBXdvwVbvNmLllXZ0lmLywGZvw1LcpDc0RHaiojIsJye.png)
解決的問題有兩個:
1)實作水準滑動的listview。重寫adapterview,上代碼:
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,以達到流暢滑動:
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>