首页 > 代码库 > 关于高仿微信对话列表滑动删除效果代码优化

关于高仿微信对话列表滑动删除效果代码优化

原文:http://blog.csdn.net/singwhatiwanna/article/details/17515543

最近公司项目需用到微信滑动拉出按钮的效果,发现一位牛人已经实现了相关效果,但控件仍与业务代码存有耦合,于是花了点时间做了些去耦合,并于此进行记录,以防遗忘。

个人认为耦合主要在于两点:

第一点是SlideListView中的onTouchEvent

通过获取item间接得到SlideView,但这样会引入外部数据类MessageItem。

    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {  
        case MotionEvent.ACTION_DOWN: {  
            int x = (int) event.getX();  
            int y = (int) event.getY();  
            //我们想知道当前点击了哪一行  
            int position = pointToPosition(x, y);  
            Log.e(TAG, "postion=" + position);  
            if (position != INVALID_POSITION) {  
                //得到当前点击行的数据从而取出当前行的item。  
                //可能有人怀疑,为什么要这么干?为什么不用getChildAt(position)?  
                //因为ListView会进行缓存,如果你不这么干,有些行的view你是得不到的。  
                MessageItem data = (MessageItem) getItemAtPosition(position);  
                mFocusedItemView = data.slideView;  
                Log.e(TAG, "FocusedItemView=" + mFocusedItemView);  
            }  
        }  
        default:  
            break;  
        }
        ...
    }

本人认为将以下代码

int position = pointToPosition(x, y);  
if (position != INVALID_POSITION) {   
    MessageItem data = (MessageItem) getItemAtPosition(position);  
    mFocusedItemView = data.slideView;  
}

修改为:

int position = pointToPosition(x, y);
if (position != INVALID_POSITION) {
    int firstPos = getFirstVisiblePosition();
    mSlideView = (SlideView) getChildAt(position - firstPos); 
}

即可。由于pointToPosition返回的是ListView所有item中被点击的item的position,而listview只会缓存可见的item,因此getChildAt()的时候,需要通过减去getFirstVisiblePosition()来计算被点击的item在可见items中的位置。如此则能够去掉外部数据类MessageItem给控件带来的耦合,同时MessageItem不再需要内部成员slideView。

public class MessageItem {  
   public int iconRes;  
   public String title;  
   public String msg;  
   public String time;   
}


第二点是slide_view_merge.xml中holder的宽度被固定为120dp

<?xml version="1.0" encoding="utf-8"?>
<merge 
    ...
    <RelativeLayout
        android:id="@+id/holder"
        android:layout_width="120dp"
        android:layout_height="match_parent"
        android:clickable="true"
        android:background="@drawable/holder_bg">

        ...
    </RelativeLayout>

</merge>

SlideView初始化时再次计算其宽度

SlideView.java:

private void initView() {  
        mContext = getContext();  
        // 初始化弹性滑动对象  
        mScroller = new Scroller(mContext);  
        // 设置其方向为横向  
        setOrientation(LinearLayout.HORIZONTAL);  
        // 将slide_view_merge加载进来  
        View.inflate(mContext, R.layout.slide_view_merge, this);  
        mViewContent = (LinearLayout) findViewById(R.id.view_content);  
        mHolderWidth = Math.round(TypedValue.applyDimension(  
                TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()  
                        .getDisplayMetrics()));  
}

本人顾虑(当然该顾虑可能是多余的)到按钮无法根据字体进行长度扩展,在SlideView初始化时提前计算holder可能所需的空间,确保按钮的可扩展性

修改如下:

<?xml version="1.0" encoding="utf-8"?>
<merge 
    ...
    <RelativeLayout
        android:id="@+id/holder"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:clickable="true"
        android:background="@drawable/holder_bg">

        ...
    </RelativeLayout>

</merge>

SlideView.java:

private void initView() {  
        mContext = getContext();  
        // 初始化弹性滑动对象  
        mScroller = new Scroller(mContext);  
        // 设置其方向为横向  
        setOrientation(LinearLayout.HORIZONTAL);  
        // 将slide_view_merge加载进来  
        View.inflate(mContext, R.layout.slide_view_merge, this);  
        mViewContent = (LinearLayout) findViewById(R.id.view_content);
        mHolder = (RelativeLayout) findViewById(R.id.holder);
        mHolder.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        mHolderWidth = mHolder.getMeasuredWidth();
        mHolder.setLayoutParams(new LinearLayout.LayoutParams(mHolderWidth, LayoutParams.FILL_PARENT));
}


总体来说,牛人的代码很简洁易用,很符合小弟的口味,十分感谢牛人的无私分享!