标签:
前言
用过微信的都知道,微信对话列表滑动删除效果是很不错的,这个效果我们也可以有。思路其实很简单,弄个ListView,然后里面的每个item做成一个可以滑动的自定义控件即可。由于ListView是上下滑动而item是左右滑动,因此会有滑动冲突,也许你需要了解下android中点击事件的派发流程,请参考Android源码分析-点击事件派发机制。我的解决思路是这样的:重写ListView的onInterceptTouchEvent方法,在move的时候做判断,如果是左右滑动就返回false,否则返回true;重写SlideView(即自定义item控件)的onTouchEvent方法来处理滑动。整个思路没有问题,滑动冲突也解决了,可是ListView无法得到焦点了,也就是ListView无法处理点击事件了。让我们回想下问题出在哪里:我的理解是这样的,上述处理滑动本身没有问题,但是有一个副作用,就是会让外层View失去焦点且无法处理点击事件。常见的滑动冲突场景,比如launcher内部嵌入ListView却是没有问题的,因为这个时候launcher不需要获得焦点,需要获得焦点的是内部的ListView。因此,上述处理方式对于外部需要获得焦点的情况(比如外部是ListView)就不太适合了。于是我就和ttdevs探讨,发现他采用了另外一种思路,我从来没有想过还可以这样玩。下面介绍他的思路。
新的思路
不考虑那么复杂,不采用主流玩法,所有的事件均由外层的ListView做拦截,同时把事件传递给SlideView做滑动,这种实现的确可以达到效果,而且代码很简单,根本不需要处理什么复杂的滑动冲突。
效果
下面分别为微信和高仿效果
代码分析
先看SlideView是如何实现的
看layout xml:
- <?xml version="1.0" encoding="utf-8"?>
- <merge xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:id="@+id/view_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
- </LinearLayout>
-
- <RelativeLayout
- android:id="@+id/holder"
- android:layout_width="120dp"
- android:layout_height="match_parent"
- android:clickable="true"
- android:background="@drawable/holder_bg">
-
- <TextView
- android:id="@+id/delete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawableLeft="@drawable/del_icon_normal"
- android:layout_centerInParent="true"
- android:gravity="center"
- android:textColor="@color/floralwhite"
- android:text="删除" />
- </RelativeLayout>
-
- </merge>
上述xml文件中,所有的view都会被放在view_content中,而holder是放置诸如删除按钮之类的东西,我们的SlideView会加载这个布局。
再看SlideView.java:
- public class SlideView extends LinearLayout {
-
- private static final String TAG = "SlideView";
-
- private Context mContext;
-
-
- private LinearLayout mViewContent;
-
-
- private RelativeLayout mHolder;
-
-
- private Scroller mScroller;
-
-
- private OnSlideListener mOnSlideListener;
-
-
- private int mHolderWidth = 120;
-
-
- private int mLastX = 0;
- private int mLastY = 0;
-
-
- private static final int TAN = 2;
-
- public interface OnSlideListener {
-
- public static final int SLIDE_STATUS_OFF = 0;
- public static final int SLIDE_STATUS_START_SCROLL = 1;
- public static final int SLIDE_STATUS_ON = 2;
-
-
- public void onSlide(View view, int status);
- }
-
- public SlideView(Context context) {
- super(context);
- initView();
- }
-
- public SlideView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initView();
- }
-
- private void initView() {
- mContext = getContext();
-
- mScroller = new Scroller(mContext);
-
- setOrientation(LinearLayout.HORIZONTAL);
-
- 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()));
- }
-
-
- public void setButtonText(CharSequence text) {
- ((TextView) findViewById(R.id.delete)).setText(text);
- }
-
-
- public void setContentView(View view) {
- mViewContent.addView(view);
- }
-
-
- public void setOnSlideListener(OnSlideListener onSlideListener) {
- mOnSlideListener = onSlideListener;
- }
-
-
- public void shrink() {
- if (getScrollX() != 0) {
- this.smoothScrollTo(0, 0);
- }
- }
-
-
-
- public void onRequireTouchEvent(MotionEvent event) {
- int x = (int) event.getX();
- int y = (int) event.getY();
- int scrollX = getScrollX();
- Log.d(TAG, "x=" + x + " y=" + y);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN: {
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
- if (mOnSlideListener != null) {
- mOnSlideListener.onSlide(this,
- OnSlideListener.SLIDE_STATUS_START_SCROLL);
- }
- break;
- }
- case MotionEvent.ACTION_MOVE: {
- int deltaX = x - mLastX;
- int deltaY = y - mLastY;
- if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
-
- break;
- }
-
-
- int newScrollX = scrollX - deltaX;
- if (deltaX != 0) {
- if (newScrollX < 0) {
- newScrollX = 0;
- } else if (newScrollX > mHolderWidth) {
- newScrollX = mHolderWidth;
- }
- this.scrollTo(newScrollX, 0);
- }
- break;
- }
- case MotionEvent.ACTION_UP: {
- int newScrollX = 0;
-
- if (scrollX - mHolderWidth * 0.75 > 0) {
- newScrollX = mHolderWidth;
- }
-
- this.smoothScrollTo(newScrollX, 0);
-
- if (mOnSlideListener != null) {
- mOnSlideListener.onSlide(this,
- newScrollX == 0 ? OnSlideListener.SLIDE_STATUS_OFF
- : OnSlideListener.SLIDE_STATUS_ON);
- }
- break;
- }
- default:
- break;
- }
-
- mLastX = x;
- mLastY = y;
- }
-
- private void smoothScrollTo(int destX, int destY) {
-
- int scrollX = getScrollX();
- int delta = destX - scrollX;
-
- mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);
- invalidate();
- }
-
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- postInvalidate();
- }
- }
-
- }
上述代码做了很详细的说明,这就是滑动控件的完整代码,大家要明白的是:你所添加的view都是加在SlideView的子View : view_content中的,而不是直接加在SlideView中,只有这样我们才方便做滑动效果。
接着看ListView的代码:核心就是下面这一个方法,将点击事件发送给SlideView处理。
- @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) {
-
-
-
- MessageItem data = (MessageItem) getItemAtPosition(position);
- mFocusedItemView = data.slideView;
- Log.e(TAG, "FocusedItemView=" + mFocusedItemView);
- }
- }
- default:
- break;
- }
-
-
- if (mFocusedItemView != null) {
- mFocusedItemView.onRequireTouchEvent(event);
- }
-
- return super.onTouchEvent(event);
- }
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17515543
最后看Activity的代码:
- public class MainActivity extends Activity implements OnItemClickListener,
- OnClickListener, OnSlideListener {
-
- private static final String TAG = "MainActivity";
-
- private ListViewCompat mListView;
-
- private List<MessageItem> mMessageItems = new ArrayList<MainActivity.MessageItem>();
-
- private SlideAdapter mSlideAdapter;
-
-
- private SlideView mLastSlideViewWithStatusOn;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- }
-
- private void initView() {
- mListView = (ListViewCompat) findViewById(R.id.list);
-
- for (int i = 0; i < 20; i++) {
- MessageItem item = new MessageItem();
- if (i % 3 == 0) {
- item.iconRes = R.drawable.default_qq_avatar;
- item.title = "腾讯新闻";
- item.msg = "青岛爆炸满月:大量鱼虾死亡";
- item.time = "晚上18:18";
- } else {
- item.iconRes = R.drawable.wechat_icon;
- item.title = "微信团队";
- item.msg = "欢迎你使用微信";
- item.time = "12月18日";
- }
- mMessageItems.add(item);
- }
- mSlideAdapter = new SlideAdapter();
- mListView.setAdapter(mSlideAdapter);
- mListView.setOnItemClickListener(this);
- }
-
- private class SlideAdapter extends BaseAdapter {
-
- private LayoutInflater mInflater;
-
- SlideAdapter() {
- super();
- mInflater = getLayoutInflater();
- }
-
- @Override
- public int getCount() {
- return mMessageItems.size();
- }
-
- @Override
- public Object getItem(int position) {
- return mMessageItems.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- SlideView slideView = (SlideView) convertView;
- if (slideView == null) {
-
- View itemView = mInflater.inflate(R.layout.list_item, null);
-
- slideView = new SlideView(MainActivity.this);
-
- slideView.setContentView(itemView);
-
- holder = new ViewHolder(slideView);
- slideView.setOnSlideListener(MainActivity.this);
- slideView.setTag(holder);
- } else {
- holder = (ViewHolder) slideView.getTag();
- }
- MessageItem item = mMessageItems.get(position);
- item.slideView = slideView;
- item.slideView.shrink();
-
- holder.icon.setImageResource(item.iconRes);
- holder.title.setText(item.title);
- holder.msg.setText(item.msg);
- holder.time.setText(item.time);
- holder.deleteHolder.setOnClickListener(MainActivity.this);
-
- return slideView;
- }
-
- }
-
- public class MessageItem {
- public int iconRes;
- public String title;
- public String msg;
- public String time;
- public SlideView slideView;
- }
-
- private static class ViewHolder {
- public ImageView icon;
- public TextView title;
- public TextView msg;
- public TextView time;
- public ViewGroup deleteHolder;
-
- ViewHolder(View view) {
- icon = (ImageView) view.findViewById(R.id.icon);
- title = (TextView) view.findViewById(R.id.title);
- msg = (TextView) view.findViewById(R.id.msg);
- time = (TextView) view.findViewById(R.id.time);
- deleteHolder = (ViewGroup) view.findViewById(R.id.holder);
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position,
- long id) {
-
- Log.e(TAG, "onItemClick position=" + position);
- }
-
- @Override
- public void onSlide(View view, int status) {
-
- if (mLastSlideViewWithStatusOn != null
- && mLastSlideViewWithStatusOn != view) {
- mLastSlideViewWithStatusOn.shrink();
- }
-
- if (status == SLIDE_STATUS_ON) {
- mLastSlideViewWithStatusOn = (SlideView) view;
- }
- }
-
- @Override
- public void onClick(View v) {
-
- if (v.getId() == R.id.holder) {
- int position = mListView.getPositionForView(v);
- if (position != ListView.INVALID_POSITION) {
- mMessageItems.remove(position);
- mSlideAdapter.notifyDataSetChanged();
- }
- Log.e(TAG, "onClick v=" + v);
- }
- }
- }
代码我都特意写了注释,就不多说了。
代码下载:http://download.csdn.net/detail/singwhatiwanna/6760085
另外此博文采用了 ttdevs 所提供代码的部分思想(他的博客是http://blog.csdn.net/ttdevs)
高仿微信对话列表滑动删除效果(转)
标签:
原文地址:http://www.cnblogs.com/chenweijie/p/4435539.html