登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 983|回复: 4

android实现QQ微信侧滑删除效果,android侧滑菜单

[复制链接]

758

主题

1386

帖子

1887

安币

手工艺人

发表于 2018-3-13 12:13:40 | 显示全部楼层 |阅读模式

            

        最近由于项目需求,需要做一个listview中的item策划删除的效果,与是查找资料和参考了一些相关的博客,终于完美实现了策划删除的效果。

        先看一下效果图(研究了半天竟然没研究出来真机上gif图怎么做,大家将就看一下吧)。

        

201712295218510.jpg

        侧滑效果图

        

201712295252247.jpg

        点击删除后的截图

        

201712295311159.jpg

        点击删除后,listview中的第一个“微信团队”被删除。

        接下来看代码部分,很多注释都在代码中,直接上代码。

        首先自定义个slideview继承linearlayout。

[Java] 查看源文件 复制代码
import android.util.attributeset; 
import android.util.log; 
import android.util.typedvalue; 
import android.view.motionevent; 
import android.view.view; 
import android.widget.linearlayout; 
import android.widget.relativelayout; 
import android.widget.scroller; 
import android.widget.textview; 
 
/**  
 * slideview 继承自linearlayout  
 */  
public class slideview extends linearlayout {  
  
  private static final string tag = "slideview";  
  
  private context mcontext;  
  
  // 用来放置所有view的容器  
  private linearlayout mviewcontent;  
  
  // 用来放置内置view的容器,比如删除 按钮  
  private relativelayout mholder;  
  
  // 弹性滑动对象,提供弹性滑动效果  
  private scroller mscroller;  
  
  // 滑动回调接口,用来向上层通知滑动事件  
  private onslidelistener monslidelistener;  
  
  // 内置容器的宽度 单位:dp  
  private int mholderwidth = 120;  
  
  // 分别记录上次滑动的坐标  
  private int mlastx = 0;  
  private int mlasty = 0;  
  
  // 用来控制滑动角度,仅当角度a满足如下条件才进行滑动:tan a = deltax / deltay > 2  
  private static final int tan = 2;  
  
  public interface onslidelistener {  
    // slideview的三种状态:开始滑动,打开,关闭  
    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);  
    // 将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()));  
  }  
  
  // 设置按钮的内容,也可以设置图标啥的,我没写  
  public void setbuttontext(charsequence text) {  
    ((textview) findviewbyid(r.id.delete)).settext(text);  
  }  
  
  // 将view加入到viewcontent中  
  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);  
    }  
  }  
  
  // 根据motionevent来进行滑动,这个方法的作用相当于ontouchevent  
  // 如果你不需要处理滑动冲突,可以直接重命名,照样能正常工作  
  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 

        自定义slideview所关联的xml.(主要就是布局侧滑显出来的删除按钮)

[Java] 查看源文件 复制代码
<

        自定义listviewcompat继承listview。

[Java] 查看源文件 复制代码
import com.ryg.slideview.mainactivity.messageitem; 
 
import android.content.context; 
import android.util.attributeset; 
import android.util.log; 
import android.view.motionevent; 
import android.view.view; 
import android.widget.listview; 
 
public class listviewcompat extends listview { 
 
  private static final string tag = "listviewcompat"; 
 
  private slideview mfocuseditemview; 
 
  public listviewcompat(context context) { 
    super(context); 
  } 
 
  public listviewcompat(context context, attributeset attrs) { 
    super(context, attrs); 
  } 
 
  public listviewcompat(context context, attributeset attrs, int defstyle) { 
    super(context, attrs, defstyle); 
  } 
 
  public void shrinklistitem(int position) { 
    view item = getchildat(position); 
 
    if (item != null) { 
      try { 
        ((slideview) item).shrink(); 
      } catch (classcastexception e) { 
        e.printstacktrace(); 
      } 
    } 
  } 
 
  @override  
  public boolean ontouchevent(motionevent event) {  
    switch (event.getaction()) {  
    case motionevent.action_down: {  
      int x = (int) event.getx();  
      int y = (int) event.gety();  
      //根据坐标获取item所在的行  
      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;  
    }  
    
    //向当前点击的view发送滑动事件请求,其实就是向slideview发请求  
    if (mfocuseditemview != null) {  
      mfocuseditemview.onrequiretouchevent(event);  
    }  
    
    return super.ontouchevent(event);  
  }  
 
} 

        接下来就是主界面的activity了

[Java] 查看源文件 复制代码
import java.util.arraylist; 
import java.util.list; 
 
import com.ryg.slideview.slideview.onslidelistener; 
 
import android.app.activity; 
import android.os.bundle; 
import android.util.log; 
import android.view.layoutinflater; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.view.viewgroup; 
import android.widget.adapterview; 
import android.widget.adapterview.onitemclicklistener; 
import android.widget.baseadapter; 
import android.widget.imageview; 
import android.widget.listview; 
import android.widget.textview; 
 
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;  
 
// 上次处于打开状态的slideview  
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 % 2 == 0) {  
    item.iconres = r.drawable.default_qq_avatar;  
    item.title = "腾讯新闻";  
    item.msg = "天津大爆炸:河北大爆炸";  
    item.time = "晚上18:00";  
  } else {  
    item.iconres = r.drawable.wechat_icon;  
    item.title = "微信团队";  
    item.msg = "欢迎你使用微信";  
    item.time = "10月01日";  
  }  
  mmessageitems.add(item);  
}  
mslideadapter = new slideadapter();  
mlistview.setadapter(mslideadapter);  
mlistview.setonitemclicklistener(this);  
}  
 
//listview 的适配器 
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) {  
    // 这里是我们的item  
    view itemview = minflater.inflate(r.layout.list_item, null);  
 
    slideview = new slideview(mainactivity.this);  
    // 这里把item加入到slideview  
    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<

        主界面中activity用到的xml

[Java] 查看源文件 复制代码
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" > 
 
  <com.ryg.slideview.listviewcompat 
    android:id="@+id/list" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#fff4f7f9" 
    android:cachecolorhint="#00000000" 
    android:divider="#dddbdb" 
    android:dividerheight="1.0px" 
    android:drawselectorontop="false" 
    android:listselector="@android:color/transparent" 
    android:scrollbars="none" /> 
 
</linearlayout>

        listview适配器的布局。

[Java] 查看源文件 复制代码
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="58dp" 
  android:background="@drawable/list_item_bg" 
  android:descendantfocusability="blocksdescendants" 
  android:gravity="center_vertical" 
  android:paddingbottom="5dp" 
  android:paddingleft="10dp" 
  android:paddingright="10dp" 
  android:paddingtop="5dp" > 
 
  <imageview 
    android:id="@+id/icon" 
    android:layout_width="50dp" 
    android:layout_height="50dp" 
    android:layout_marginright="5dp" 
    android:src="@drawable/wechat_icon" /> 
 
  <textview 
    android:id="@+id/title" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_torightof="@id/icon" 
    android:textcolor="@color/black" 
    android:textsize="15sp" /> 
 
  <textview 
    android:id="@+id/msg" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignbottom="@id/icon" 
    android:layout_alignleft="@id/title" 
    android:textcolor="@color/grey" /> 
 
  <textview 
    android:id="@+id/time" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignparentright="true" 
    android:layout_aligntop="@id/title" 
    android:textcolor="@color/grey" /> 
 
</relativelayout>

        附drawable目录下的xml文件
holder_bg.xml

[Java] 查看源文件 复制代码
<

        list_item_bg.xml.

[Java] 查看源文件 复制代码
<

        还有一些对color颜色的定义,这里就不贴了,大家可以直接换成颜色的代码就可以。



        

579

主题

1248

帖子

3282

安币

手工艺人

发表于 2018-3-14 06:18:19 | 显示全部楼层
不错不错,楼主辛苦了。。。

85

主题

9755

帖子

2215

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-15 06:17:28 | 显示全部楼层
安卓巴士是个不错的网站,我来顶个贴~

314

主题

982

帖子

704

安币

手工艺人

发表于 2018-3-16 11:31:47 | 显示全部楼层
感觉楼主很用心,辛苦啦~

0

主题

310

帖子

4514

安币

码皇(巴士元老)

Rank: 8Rank: 8

发表于 2019-1-31 17:37:29 | 显示全部楼层
感谢分享,安卓巴士有你更精彩:)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区
联系我们
关闭
合作电话:
15618560077
Email:
805941275@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表