Android--listview的item侧滑的实现

时间:2023-01-08 19:33:45

前段时间的状态不是很好,和房东有一些矛盾,同时又犯了厌倦上班综合症。好在及时调整了心态,接下来还有继续努力。
好了,现在总结下前段时间前段时间自己学到的知识。

先是在郭霖大神的blog上看到了他对侧滑菜单的实现,自己就在想能不能实现了listview上item的侧滑。
最后虽然实现了效果,但是侧滑效果不是特别的流畅,还有待优化。

具体思想就是郭林大神博客中的思想。
效果大致如下:
Android--listview的item侧滑的实现
基本思想是自定义一个view作为listview的子布局。

1.先完成这个自定义的view

/**
* Created by gejiahui on 2015/9/8.
*/

public class ItemSlideLayout extends LinearLayout implements View.OnTouchListener{

private int screenWith;

private float xDown;

private float xMove;

private float xUp;

private int rightViewWidth = 200;

private int leftEdge = -rightViewWidth;

private View leftView;

private View rightView;

private final int rightEgde=0;

private boolean isRightVisibily=false;
/**
* 左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。
*/

private MarginLayoutParams leftParams;

/**
* 右侧布局的参数,通过此参数来重新确定右侧布局的宽度。
*/

private MarginLayoutParams rightParams;

/**
* 用于监听侧滑事件的View。
*/

private View mBindView;

public ItemSlideLayout(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
screenWith = wm.getDefaultDisplay().getWidth();
}


public void setSrollView(View view)
{
mBindView = view;
mBindView.setOnTouchListener(this);
}

/**
* 在onLayout中重新设定左侧布局和右侧布局的参数。
*/

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed)
{
//get left view
leftView = getChildAt(0);
leftParams = (MarginLayoutParams) leftView.getLayoutParams();
leftParams.leftMargin = 0;
leftParams.width = screenWith;
leftView.setLayoutParams(leftParams);

rightView = getChildAt(1);
rightParams = (MarginLayoutParams) rightView.getLayoutParams();
rightParams.width = rightViewWidth;
rightView.setLayoutParams(rightParams);

}

}

@Override
public boolean onTouch(View v, MotionEvent event) {

switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
// 手指按下时,记录按下时的横坐标
xDown = event.getRawX();
break;

case MotionEvent.ACTION_MOVE:
// 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整左侧布局的leftMargin值,从而显示和隐藏左侧布局
xMove = event.getRawX();
int distanceX = (int) (xMove - xDown);
if(isRightVisibily)
{
leftParams.leftMargin = distanceX + leftEdge;
}
else
{
leftParams.leftMargin = distanceX;
}
if(leftParams.leftMargin < leftEdge)
{
leftParams.leftMargin = leftEdge;
}
if(leftParams.leftMargin > rightEgde)
{
leftParams.leftMargin = rightEgde;
}
leftView.setLayoutParams(leftParams);
break;

case MotionEvent.ACTION_UP:

xUp = event.getRawX();
if (wantToShowRightLayout())
{
if(shouldScrollToRightLayout())
{
scrollToRightLayout();
}else
{
scrollToLeftLayout();
}

}
if(wantToShowLeftLayout())
{
if(shouldScrollToLeft())
{
scrollToLeftLayout();
}else
{
scrollToRightLayout();
}
}

break;
}

return true;
}

/**
* 将屏幕滚动到左侧布局界面,滚动速度设定为30.
*/

public void scrollToLeftLayout() {
new ScrollTask().execute(30);
}

/**
* 将屏幕滚动到右侧布局界面,滚动速度设定为-30.
*/

public void scrollToRightLayout() {
new ScrollTask().execute(-30);
}
/**
*
* @return 当前手势想显示右侧布局返回true,否则返回false。
*/

private boolean wantToShowRightLayout()
{
return xMove - xDown < 0 && !isRightVisibily;
}

/**
*
*
* @return 当前手势想显示左侧布局返回true,否则返回false。
*/

private boolean wantToShowLeftLayout()
{
return xMove - xDown > 0 && isRightVisibily;
}


/**

*
* @return 如果应该滚动将左侧布局展示出来返回true,否则返回false。
*/

private boolean shouldScrollToRightLayout() {
return xDown -xUp > 100;
}

/**
*
* @return 如果应该滚动将右侧布局展示出来返回true,否则返回false。
*/

private boolean shouldScrollToLeft() {
return xUp - xMove > 100;
}

class ScrollTask extends AsyncTask<Integer, Integer, Integer> {

@Override
protected Integer doInBackground(Integer... speed) {
int leftMargin = leftParams.leftMargin;
// 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。
while (true) {
leftMargin = leftMargin + speed[0];
if (leftMargin > rightEgde) {
leftMargin = rightEgde;
break;
}
if (leftMargin < leftEdge) {
leftMargin = leftEdge;
break;
}
publishProgress(leftMargin);
// 为了要有滚动效果产生,每次循环使线程睡眠20毫秒,这样肉眼才能够看到滚动动画。
sleep(20);
}
if (speed[0] > 0) {
isRightVisibily = false;
} else {
isRightVisibily = true;
}
return leftMargin;
}

@Override
protected void onProgressUpdate(Integer... leftMargin) {
leftParams.leftMargin = leftMargin[0];
leftView.setLayoutParams(leftParams);
}

@Override
protected void onPostExecute(Integer leftMargin) {
leftParams.leftMargin = leftMargin;
leftView.setLayoutParams(leftParams);
}
}

/**
* 使当前线程睡眠指定的毫秒数。
*
* @param millis
* 指定当前线程睡眠多久,以毫秒为单位
*/

private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}


}

这个布局的思想是实现郭霖的一篇博文,有兴趣的可以去郭大神的blog下查看一下,讲的非常细致。

2.完成布局文件和适配器
布局文件就是简单的listview,item布局就是上面的ItemSlideLayout
下面给过适配器的代码:

public class MyAdapter extends ArrayAdapter<String> {

Context context;
ArrayList<String> datas;
ItemSlideLayout iTemSlideLayout;

public MyAdapter(Context context, int resource, List<String> objects) {
super(context, resource, objects);
this.context=context;
datas= (ArrayList<String>) objects;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

View view = null;

if(convertView == null)
{
view = LayoutInflater.from(this.context).inflate(R.layout.item,parent,false);
}
else
{
view = convertView;
}


TextView txt = (TextView)view.findViewById(R.id.txt);
txt.setText(getItem(position));
TextView delete = (TextView)view.findViewById(R.id.delete);
delete.setOnTouchListener(new View.OnTouchListener() {


@Override
public boolean onTouch(View v, MotionEvent event) {
datas.remove( position);
notifyDataSetChanged();
return false;
}
});
iTemSlideLayout =(ItemSlideLayout)view.findViewById(R.id.item_slide);
iTemSlideLayout.setSrollView(txt);

return view;
}
}

3.主函数的xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">

<com.gejiahui.itemslide.MyListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.gejiahui.itemslide.MyListView>

</LinearLayout>

这里的MyListView就是继承了listview,只是简单重写的它的onInterceptTouchEvent来修改它的分发机制。

/**
* Created by gejiahui on 2015/9/9.
*/

public class MyListView extends ListView {
float xDown,yDown;
float xUp ,yUp ;
boolean result = false;
public MyListView(Context context) {
super(context);
}

public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

switch(ev.getAction())
{
case MotionEvent.ACTION_DOWN:
xDown = ev.getRawX();
yDown = ev.getRawY();
Log.v("down1", "" + xDown + " : " + yDown);
break;


case MotionEvent.ACTION_MOVE:
xUp = ev.getRawX();
yUp = ev.getRawY();
Log.v("movw2", "" + xUp + " : " + yUp);

break;
case MotionEvent.ACTION_UP:
xUp = ev.getRawX();
yUp = ev.getRawY();
Log.v("UP2", "" + xUp + " : " + yUp);
break;
}

float x,y;
x = Math.abs(xUp - xDown);
y = Math.abs(yUp - yDown);
Log.v("many3",""+ x+ " : "+y);
if(x >= y)
{
return false;
}else
{
return true;
}

}
}

我的想法很简单,就是横着滑的距离大于竖着的时候,分发到item的自定义的ItemSlideLayout来响应;
当横滑的距离小于竖滑的距离时候,有listview来响应。
至于android的分发机制,可以点 这里

源代码下载,点 这里

如有错误,欢迎指正,不胜感激。