Android--listview的item侧滑的实现

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

先是在郭霖大神的blog上看到了他对侧滑菜单的实现,自己就在想能不能实现了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的分发机制,可以点 这里

源代码下载,点 这里

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值