最近公司项目需用到微信滑动拉出按钮的效果,发现一位牛人已经实现了相关效果,但控件仍与业务代码存有耦合,于是花了点时间做了些去耦合,并于此进行记录,以防遗忘。
个人认为耦合主要在于两点:
第一点是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)); }
总体来说,牛人的代码很简洁易用,很符合小弟的口味,十分感谢牛人的无私分享!
关于高仿微信对话列表滑动删除效果代码优化,布布扣,bubuko.com
原文:http://my.oschina.net/u/1867023/blog/293653