Android仿微信对话列表滑动删除效果

微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果。

实现原理
 1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView
 2.在onTouchEvent中计算要滑动的距离,调用swipeView.scrollTo即可。

运行效果如下

下面是最核心的部分SwipeListView代码:

package com.fxsky.swipelist.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

import com.fxsky.swipelist.R;

public class SwipeListView extends ListView {
 private Boolean mIsHorizontal;

 private View mPreItemView;

 private View mCurrentItemView;

 private float mFirstX;

 private float mFirstY;

 private int mRightViewWidth;

 // private boolean mIsInAnimation = false;
 private final int mDuration = 100;

 private final int mDurationStep = 10;

 private boolean mIsShown;

 public SwipeListView(Context context) {
 this(context,null);
 }

 public SwipeListView(Context context, AttributeSet attrs) {
 this(context, attrs,0);
 }

 public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);

 TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
 R.styleable.swipelistviewstyle); 

 //获取自定义属性和默认值
 mRightViewWidth = (int) mTypedArray.getDimension(R.styleable.swipelistviewstyle_right_width, 200); 

 mTypedArray.recycle();
 }

 /**
 * return true, deliver to listView. return false, deliver to child. if
 * move, return true
 */
 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
 float lastX = ev.getX();
 float lastY = ev.getY();
 switch (ev.getAction()) {
 case MotionEvent.ACTION_DOWN:
 mIsHorizontal = null;
 System.out.println("onInterceptTouchEvent----->ACTION_DOWN");
 mFirstX = lastX;
 mFirstY = lastY;
 int motionPosition = pointToPosition((int)mFirstX, (int)mFirstY);

 if (motionPosition >= 0) {
  View currentItemView = getChildAt(motionPosition - getFirstVisiblePosition());
  mPreItemView = mCurrentItemView;
  mCurrentItemView = currentItemView;
 }
 break;

 case MotionEvent.ACTION_MOVE:
 float dx = lastX - mFirstX;
 float dy = lastY - mFirstY;

 if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {
  return true;
 }
 break;

 case MotionEvent.ACTION_UP:
 case MotionEvent.ACTION_CANCEL:
 System.out.println("onInterceptTouchEvent----->ACTION_UP");
 if (mIsShown && (mPreItemView != mCurrentItemView || isHitCurItemLeft(lastX))) {
  System.out.println("1---> hiddenRight");
  /**
  * 情况一:
  * <p>
  * 一个Item的右边布局已经显示,
  * <p>
  * 这时候点击任意一个item, 那么那个右边布局显示的item隐藏其右边布局
  */
  hiddenRight(mPreItemView);
 }
 break;
 }

 return super.onInterceptTouchEvent(ev);
 }

 private boolean isHitCurItemLeft(float x) {
 return x < getWidth() - mRightViewWidth;
 }

 /**
 * @param dx
 * @param dy
 * @return judge if can judge scroll direction
 */
 private boolean judgeScrollDirection(float dx, float dy) {
 boolean canJudge = true;

 if (Math.abs(dx) > 30 && Math.abs(dx) > 2 * Math.abs(dy)) {
 mIsHorizontal = true;
 System.out.println("mIsHorizontal---->" + mIsHorizontal);
 } else if (Math.abs(dy) > 30 && Math.abs(dy) > 2 * Math.abs(dx)) {
 mIsHorizontal = false;
 System.out.println("mIsHorizontal---->" + mIsHorizontal);
 } else {
 canJudge = false;
 }

 return canJudge;
 }

 /**
 * return false, can't move any direction. return true, cant't move
 * vertical, can move horizontal. return super.onTouchEvent(ev), can move
 * both.
 */
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
 float lastX = ev.getX();
 float lastY = ev.getY();

 switch (ev.getAction()) {
 case MotionEvent.ACTION_DOWN:
 System.out.println("---->ACTION_DOWN");
 break;

 case MotionEvent.ACTION_MOVE:
 float dx = lastX - mFirstX;
 float dy = lastY - mFirstY;

 // confirm is scroll direction
 if (mIsHorizontal == null) {
  if (!judgeScrollDirection(dx, dy)) {
  break;
  }
 }

 if (mIsHorizontal) {
  if (mIsShown && mPreItemView != mCurrentItemView) {
  System.out.println("2---> hiddenRight");
  /**
  * 情况二:
  * <p>
  * 一个Item的右边布局已经显示,
  * <p>
  * 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局
  * <p>
  * 向左滑动只触发该情况,向右滑动还会触发情况五
  */
  hiddenRight(mPreItemView);
  }

  if (mIsShown && mPreItemView == mCurrentItemView) {
  dx = dx - mRightViewWidth;
  System.out.println("======dx " + dx);
  }

  // can't move beyond boundary
  if (dx < 0 && dx > -mRightViewWidth) {
  mCurrentItemView.scrollTo((int)(-dx), 0);
  }

  return true;
 } else {
  if (mIsShown) {
  System.out.println("3---> hiddenRight");
  /**
  * 情况三:
  * <p>
  * 一个Item的右边布局已经显示,
  * <p>
  * 这时候上下滚动ListView,那么那个右边布局显示的item隐藏其右边布局
  */
  hiddenRight(mPreItemView);
  }
 }

 break;

 case MotionEvent.ACTION_UP:
 case MotionEvent.ACTION_CANCEL:
 System.out.println("============ACTION_UP");
 clearPressedState();
 if (mIsShown) {
  System.out.println("4---> hiddenRight");
  /**
  * 情况四:
  * <p>
  * 一个Item的右边布局已经显示,
  * <p>
  * 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局
  */
  hiddenRight(mPreItemView);
 }

 if (mIsHorizontal != null && mIsHorizontal) {
  if (mFirstX - lastX > mRightViewWidth / 2) {
  showRight(mCurrentItemView);
  } else {
  System.out.println("5---> hiddenRight");
  /**
  * 情况五:
  * <p>
  * 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,隐藏之。
  */
  hiddenRight(mCurrentItemView);
  }

  return true;
 }

 break;
 }

 return super.onTouchEvent(ev);
 }

 private void clearPressedState() {
 // TODO current item is still has background, issue
 mCurrentItemView.setPressed(false);
 setPressed(false);
 refreshDrawableState();
 // invalidate();
 }

 private void showRight(View view) {
 System.out.println("=========showRight");

 Message msg = new MoveHandler().obtainMessage();
 msg.obj = view;
 msg.arg1 = view.getScrollX();
 msg.arg2 = mRightViewWidth;
 msg.sendToTarget();

 mIsShown = true;
 }

 private void hiddenRight(View view) {
 System.out.println("=========hiddenRight");
 if (mCurrentItemView == null) {
 return;
 }
 Message msg = new MoveHandler().obtainMessage();//
 msg.obj = view;
 msg.arg1 = view.getScrollX();
 msg.arg2 = 0;

 msg.sendToTarget();

 mIsShown = false;
 }

 /**
 * show or hide right layout animation
 */
 @SuppressLint("HandlerLeak")
 class MoveHandler extends Handler {
 int stepX = 0;

 int fromX;

 int toX;

 View view;

 private boolean mIsInAnimation = false;

 private void animatioOver() {
 mIsInAnimation = false;
 stepX = 0;
 }

 @Override
 public void handleMessage(Message msg) {
 super.handleMessage(msg);
 if (stepX == 0) {
 if (mIsInAnimation) {
  return;
 }
 mIsInAnimation = true;
 view = (View)msg.obj;
 fromX = msg.arg1;
 toX = msg.arg2;
 stepX = (int)((toX - fromX) * mDurationStep * 1.0 / mDuration);
 if (stepX < 0 && stepX > -1) {
  stepX = -1;
 } else if (stepX > 0 && stepX < 1) {
  stepX = 1;
 }
 if (Math.abs(toX - fromX) < 10) {
  view.scrollTo(toX, 0);
  animatioOver();
  return;
 }
 }

 fromX += stepX;
 boolean isLastStep = (stepX > 0 && fromX > toX) || (stepX < 0 && fromX < toX);
 if (isLastStep) {
 fromX = toX;
 }

 view.scrollTo(fromX, 0);
 invalidate();

 if (!isLastStep) {
 this.sendEmptyMessageDelayed(0, mDurationStep);
 } else {
 animatioOver();
 }
 }
 }

 public int getRightViewWidth() {
 return mRightViewWidth;
 }

 public void setRightViewWidth(int mRightViewWidth) {
 this.mRightViewWidth = mRightViewWidth;
 }
}

Demo下载地址:http://xiazai.jb51.net/201608/yuanma/SwipeListView(jb51.net).rar

Demo中SwipeAdapter源码中有一处由于粗心写错了,会导致向下滑动时出现数组越界异常,现更正如下:

@Override
 public int getCount() {
// return 100;
 return data.size();
 }

本文已被整理到了《Android微信开发教程汇总》,欢迎大家学习阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现可浏览和搜索的联系人列表

    通过这篇文章,我想说明一下如何创建一个可搜索的"联系人列表"Android应用程序.使用这个应用程序,用户可以通过使用导航按钮浏览所有保存的联系人和根据联系人名称搜索联系人.该应用程序还可以显示联系人的照片(如果可用). 要浏览联系人列表可以使用<<,<,>和>>按钮. 要搜索联系人的用户在"搜索名称"文本框中键入联系人名称,然后单击"搜索"按钮.点击"清除搜索"按钮,清除"搜索名

  • Android高仿微信对话列表滑动删除效果

    前言 用过微信的都知道,微信对话列表滑动删除效果是很不错的,这个效果我们也可以有.思路其实很简单,弄个ListView,然后里面的每个item做成一个可以滑动的自定义控件即可.由于ListView是上下滑动而item是左右滑动,因此会有滑动冲突,也许你需要了解下android中点击事件的派发流程,请参考Android源码分析-点击事件派发机制.我的解决思路是这样的:重写ListView的onInterceptTouchEvent方法,在move的时候做判断,如果是左右滑动就返回false,否则返

  • Android自定义View实现通讯录字母索引(仿微信通讯录)

    一.效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,QQ,还有美团选择地区等等.这里我截了一张美团选择城市的图片来看看: 我们今天就来实现图片中右侧模块的索引功能,包括触摸显示以选中的索引字母.这里我的UI界面主要是参照微信的界面来实现,所以各位也可以对照微信来看看效果,什么都不说了,只有效果图最具有说服力! 二.分析: 我们看到这样的效果我们心理都回去琢磨,他是如何实现的: 首先,它肯定是通过自定义 View 来实现的,因为 Android 没有提供类似这样的控件

  • Android手机联系人带字母索引的快速查找

    喜欢另辟蹊径的我,在这里废话不多说了,直接上代码和图片了. 效果图如下: 第一步:MainActivity的代码如下: package net.loonggg.test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.TreeSet; import android.os.Bundle; import and

  • JavaScript仿微信(电话)联系人列表滑动字母索引实例讲解(推荐)

    今天做到了一个联系人列表的需求, 要求和微信的一样! 写出来分享给大家, 使用了jq和doT模版引擎 首先对数据源进行数据排序 // 数据排序 function sortData(data) { var letterArr = []; for (var i = 0; i < data.length; i++) { for (var j = 0; j < data.length; j++) { if (data[i].flag < data[j].flag) { var temp = da

  • Android仿微信联系人列表字母侧滑控件

    仿微信联系人列表字母侧滑控件, 侧滑控件参考了以下博客: Android实现ListView的A-Z字母排序和过滤搜索功能 首先分析一下字母侧滑控件应该如何实现,根据侧滑控件的高度和字母的数量来平均计算每个字母应该占据的高度. 在View的onDraw()方法下绘制每一个字母 protected void onDraw(Canvas canvas) { super.onDraw(canvas); int height = getHeight();// 获取对应高度 int width = get

  • iOS tabview如何添加字母索引

    本文实例为大家分享了iOS tabview添加字母索引的具体代码,供大家参考,具体内容如下 文章转载自大神源码传送门 1.将汉字转换成首字母 //系统获取首字母 - (NSString *) pinyinFirstLetter:(NSString*)sourceString { NSMutableString *source = [sourceString mutableCopy]; CFStringTransform((__bridge CFMutableStringRef)source, N

  • android开发教程之使用listview显示qq联系人列表

    首先还是xml布局文件,在其中添加ListView控件: 主布局layout_main.xml 复制代码 代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"

  • Android仿微信对话列表滑动删除效果

    微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果. 实现原理  1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView  2

  • Android仿微信通讯录列表侧边栏效果

    先看Android仿微信通讯录列表侧边栏效果图 这是比较常见的效果了吧 列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位. 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包--pinyin4j-2.5.0即可 首先,先来定义侧边栏控件View,只要直接画出来即可. 字母选中项会变为红色,且滑动时背景会变色,此时SideBar并不包含居中的提示文本 public class SideBar extends View { priva

  • android仿微信好友列表功能

    android studio实现微信好友列表功能,注意有一个jar包我没有放上来,请大家到MainActivity中的那个网址里面下载即可,然后把pinyin4j-2.5.0.jar复制粘贴到项目的app/libs文件夹里面,然后clean项目就可以使用了 实现效果图: (1)在build.gradle中引用第三方的类库 compile 'com.android.support:recyclerview-v7:26.0.0-alpha1' compile files('libs/pinyin4j

  • Android仿微信底部按钮滑动变色

    Android仿微信底部按钮滑动变色,这里只针对使用Fragment为Tab页的滑动操作,进行简单的变色讲解. 首先说下OnPageChangeListener这个监听 //这个监听有三个方法 public abstract void onPageScrollStateChanged (int state) public abstract void onPageScrolled (int position, float positionOffset, int positionOffsetPixe

  • Android仿微信5实现滑动导航条

    本文实例为大家分享了Android 仿微信5滑动导航效果,供大家参考,具体内容如下 ViewPageAdapter.java package com.rong; import java.util.ArrayList; import java.util.List; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; publi

  • Android仿微信视屏悬浮窗效果

    在项目中需要对接入的腾讯云音视频,可以悬浮窗显示,悬浮窗可拖拽,并且在悬浮窗不影响其他的activity的焦点. 这个大神的文章Android基于腾讯云实时音视频仿微信视频通话最小化悬浮,他讲的是视频通话时,将远端视频以悬浮窗形式展示,根据他的代码我进行了部分简化 1.悬浮窗效果:点击缩小按钮,将当前远端视屏加载进悬浮窗,且悬浮窗可拖拽,不影响其他界面焦点:点击悬浮窗可返回原来的Activity 2.实现悬浮窗需要: 在androidManifest中申请悬浮窗权限<uses-permissio

  • Android仿微信微博多图展示效果

    1.简介 这是一个用于实现像微信朋友圈和微博的类似的九宫格图片展示控件,通过自定义viewgroup实现,使用方便. 多图根据屏幕适配,单张图片时需要自己指定图片的宽高: 2.使用方法 引用: compile 'com.w4lle.library:NineLayout:1.0.0' 使用: 在项目的layout文件中添加如下xml即可加入到布局文件 <com.w4lle.library.NineGridlayout android:layout_marginTop="8dp" a

  • Android实现微信首页左右滑动切换效果

    大家看到微信首页切换效果有没有觉得很炫,滑动切换,点击底部bar瞬间切换,滑动切换渐变效果,线上效果图: 之前也在博客上看到别人的实现,再次基础上,我做了些优化.首先说下实现原理,大神略过,o(╯□╰)o 页面上看到的三个页面是三个Fragment, 左右滑动使用viewpager,相信大家也都是这么再用,那么底部用的是什么技术呢,底部渐变其实就是重写了ImageView,以及在左右滑动时,改变了TextView的颜色值,是不是很简单...下面我们一步一步的来: 1.自定义ImageView:

随机推荐