Android开发-自定义View-AndroidStudio(十六)侧滑删除
2016-12-29 16:23
495 查看
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/53929510
觉得博文有用,请点赞,请评论,请关注,谢谢!~
项目源码下载:http://download.csdn.net/detail/iwanghang/9724693
老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
其实最近几篇博客写得不是很好,代码已经不太适合初学者来阅读,很多地方刚接触Android的同学可能还需要查资料,才能理解。
从这篇博文开始,博主把所有可能需要查资料的地方,都写在注释里,起码看了就明白意思,减少大家查资料的时间。
争取做到,复制代码就去用,不懂的地方几乎不用查资料,直接从注释里就能得到答案。让我们共同进步~
MainActivity.java:
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/53929510
欢迎移动开发爱好者交流
沈阳或周边城市公司有意开发Android,请与我联系
联系方式
微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com
项目源码下载:http://download.csdn.net/detail/iwanghang/9724693
觉得博文有用,请点赞,请评论,请关注,谢谢!~
觉得博文有用,请点赞,请评论,请关注,谢谢!~
项目源码下载:http://download.csdn.net/detail/iwanghang/9724693
老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
其实最近几篇博客写得不是很好,代码已经不太适合初学者来阅读,很多地方刚接触Android的同学可能还需要查资料,才能理解。
从这篇博文开始,博主把所有可能需要查资料的地方,都写在注释里,起码看了就明白意思,减少大家查资料的时间。
争取做到,复制代码就去用,不懂的地方几乎不用查资料,直接从注释里就能得到答案。让我们共同进步~
MainActivity.java:
package com.iwanghang.slidedemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private ListView lv_main; private ArrayList<MyBean> myBeans; private MyAdapter myAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_main = (ListView) findViewById(R.id.lv_main); // 设置适配器 // 准备数据 myBeans = new ArrayList<>(); for(int i=0;i<100;i++){ myBeans.add(new MyBean("iwanghang~"+i)); } myAdapter = new MyAdapter(); lv_main.setAdapter(myAdapter); } class MyAdapter extends BaseAdapter{ @Override public int getCount() { return myBeans.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } /** * ViewHolder的解释: * 1、只是一个静态类,不是Android的API方法。 * 2、它的作用就在于减少不必要的调用findViewById,然后把对底下的控件引用存在ViewHolder里面,再在 * View.setTag(holder)把它放在view里,下次就可以直接取了。 */ @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if(convertView == null){ convertView = View.inflate(MainActivity.this,R.layout.item_main,null); viewHolder = new ViewHolder(); viewHolder.item_content = (TextView) convertView.findViewById(R.id.item_content); viewHolder.item_menu = (TextView) convertView.findViewById(R.id.item_menu); /** * setTag * 把查找的view缓存起来方便多次重用 * 相当于给View对象的一个标签。XX标签可以是任何内容,我们这里把他设置成了一个对象XX。 * * Tag的作用就是设置标签,标签可以是任意玩意。 * 以及convertView是如何在程序中使代码运行变的效率的:利用缓存convertView尽可能少实例化 * 同样结构体的对象; */ convertView.setTag(viewHolder); }else{ viewHolder = (ViewHolder) convertView.getTag(); } // 根据位置得到内容 final MyBean myBean = myBeans.get(position); viewHolder.item_content.setText(myBean.getName()); viewHolder.item_content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MyBean myBean1 = myBeans.get(position); Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show(); System.out.println("MainActivity---onClick"); } }); viewHolder.item_menu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { /** * getParent() 获取父组件 * 获取爷爷组件,可以使用getParent().getParent() */ SlideLayout slideLayout = (SlideLayout) view.getParent(); slideLayout.closeMenu(); myBeans.remove(myBean); notifyDataSetChanged(); System.out.println("MainActivity---remove"); } }); SlideLayout slideLayout = (SlideLayout) convertView; slideLayout.setOnStateChangeListener(new MyOnStateChangeListener()); return convertView; } } private SlideLayout slideLayout; class MyOnStateChangeListener implements SlideLayout.OnStateChangeListener { @Override public void onClose(SlideLayout layout) { if(slideLayout == layout){ slideLayout = null; } } @Override public void onDown(SlideLayout layout) { if(slideLayout!=null && slideLayout!=layout){ slideLayout.closeMenu(); } } @Override public void onOpen(SlideLayout layout) { slideLayout = layout; } } /** * ViewHolder的解释: * 1、只是一个静态类,不是Android的API方法。 * 2、它的作用就在于减少不必要的调用findViewById,然后把对底下的控件引用存在ViewHolder里面,再在 * View.setTag(holder)把它放在view里,下次就可以直接取了。 */ static class ViewHolder{ TextView item_content; TextView item_menu; } }SlideLayout.java:
package com.iwanghang.slidedemo; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.Scroller; public class SlideLayout extends FrameLayout { private static final String TAG = SlideLayout.class.getSimpleName(); private View contentView; private View menuView; /** * 滚动者 */ private Scroller scroller; /** * Content的宽 */ private int contentWidth; private int menuWidth; private int viewHeight; // 他们的高都是相同的 public SlideLayout(Context context, AttributeSet attrs) { super(context, attrs); scroller = new Scroller(context); } /** * 当布局文件加载完成的时候回调这个方法 */ @Override protected void onFinishInflate() { super.onFinishInflate(); contentView = getChildAt(0); menuView = getChildAt(1); } /** * 在测量方法里,得到各个控件的高和宽 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); contentWidth = contentView.getMeasuredWidth(); menuWidth = menuView.getMeasuredWidth(); viewHeight = getMeasuredHeight(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 指定菜单的位置 menuView.layout(contentWidth, 0, contentWidth + menuWidth, viewHeight); } private float startX; private float startY; private float downX; // 只赋值一次 private float downY; @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 1.按下记录坐标 downX = startX = event.getX(); downY = startY = event.getY(); Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_MOVE"); // 2.记录结束值 float endX = event.getX(); float endY = event.getY(); // 3.计算偏移量 float distanceX = endX - startX; int toScrollX = (int) (getScrollX() - distanceX); if (toScrollX < 0) { toScrollX = 0; } else if (toScrollX > menuWidth) { toScrollX = menuWidth; } scrollTo(toScrollX, getScrollY()); startX = event.getX(); startY = event.getY(); // 在X轴和Y轴滑动的距离 float DX = Math.abs(endX-downX); float DY = Math.abs(endY-downY); if(DX>DY && DX>8){ // 水平方向滑动 // 响应侧滑 // 反拦截-事件给SlideLayout getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_UP"); int totalScrollX = getScrollX();//偏移量 if(totalScrollX < menuWidth/2){ // 关闭Menu closeMenu(); }else{ // 打开Menu openMenu(); } break; } return true; } /** * true:拦截孩子的事件,但会执行当前控件的onTouchEvent()方法 * false:不拦截孩子的事件,事件继续传递 */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean intercept = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 1、按下记录坐标 downX = startX = event.getX(); Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_DOWN"); if(onStateChangeListener != null){ onStateChangeListener.onDown(this); } break; case MotionEvent.ACTION_MOVE: Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_MOVE"); // 2、记录结束值 float endX = event.getX(); float endY = event.getY(); // 3、计算偏移量 float distanceX = endX - startX; startX = event.getX(); // 在X轴和Y轴滑动的距离 float DX = Math.abs(endX-downX); if(DX>8){ intercept = true; } break; case MotionEvent.ACTION_UP: break; } return intercept; } /** * 打开menu */ public void openMenu() { // --->menuWidth int distanceX = menuWidth - getScrollX(); scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY()); invalidate(); // 强制刷新 System.out.println("SlideLayout---openMenu"); if(onStateChangeListener != null){ onStateChangeListener.onOpen(this); } } /** * 关闭menu */ public void closeMenu() { // --->0 int distanceX = 0 - getScrollX(); scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY()); invalidate(); // 强制刷新 System.out.println("SlideLayout---closeMenu"); if(onStateChangeListener != null){ onStateChangeListener.onClose(this); } } /** * computeScroll:主要功能是计算拖动的位移量、更新背景、设置要显示的屏幕(setCurrentScreen(mCurrentScreen);)。 * 重写computeScroll()的原因:调用startScroll()是不会有滚动效果的,只有在computeScroll()获取滚动情况,做出滚动的响应 */ @Override public void computeScroll() { super.computeScroll(); if(scroller.computeScrollOffset()){ scrollTo(scroller.getCurrX(),scroller.getCurrY()); invalidate(); System.out.println("SlideLayout---computeScroll"); } } /** * 接口回调 * 监听SlideLayout状态的改变 */ public interface OnStateChangeListener{ void onClose(SlideLayout layout); void onDown(SlideLayout layout); void onOpen(SlideLayout layout); } private OnStateChangeListener onStateChangeListener; /** * 设置SlideLayout状态的监听 */ public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) { this.onStateChangeListener = onStateChangeListener; } }MyBean.java:
package com.iwanghang.slidedemo; public class MyBean { private String name; public MyBean(String name) { this.name = name; } public String getName() { return name; } }activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <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="match_parent" tools:context="com.iwanghang.slidedemo.MainActivity"> <ListView android:id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>item_main.xml
<?xml version="1.0" encoding="utf-8"?> <com.iwanghang.slidedemo.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp"> <include android:id="@+id/item_content" layout="@layout/item_content"/> <include android:id="@+id/item_menu" layout="@layout/item_menu"/> </com.iwanghang.slidedemo.SlideLayout>item_content.xml
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:background="#44000000" android:gravity="center" android:text="Content" android:textColor="#000000" android:textSize="25sp"> </TextView>item_menu.xml
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="60dp" android:background="#22000000" android:gravity="center" android:text="Delete" android:textColor="#ff0000" android:textSize="25sp"> </TextView>
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/53929510
欢迎移动开发爱好者交流
沈阳或周边城市公司有意开发Android,请与我联系
联系方式
微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com
项目源码下载:http://download.csdn.net/detail/iwanghang/9724693
觉得博文有用,请点赞,请评论,请关注,谢谢!~
相关文章推荐
- Android开发-自定义View-AndroidStudio(十六)侧滑删除
- Android开发-自定义View-AndroidStudio(一)
- Android开发-自定义View-AndroidStudio(二)遇到问题,附:ScrollView中文API
- Android开发-自定义View-AndroidStudio(六)ViewPager再体验
- Android开发-自定义View-AndroidStudio(五)ViewPager初体验
- Android开发-自定义View-AndroidStudio(十二)仿ViewPager(2)
- Android开发-自定义View-AndroidStudio(一)
- Android开发-自定义View-AndroidStudio(七)popupwindow
- Android开发-自定义View-AndroidStudio(十)仿ViewPager(1)
- Android开发-自定义View-AndroidStudio(八)自定义View初体验
- Android开发-自定义View-AndroidStudio(九)手势监听类GestureDetector
- android自定义侧滑LisitView(包含编辑、删除)
- Android自定义可编辑、删除的侧滑LisitView
- Android开发-自定义View-AndroidStudio(五)ViewPager初体验
- Android开发-自定义View-AndroidStudio(十一)有趣的BUG
- Android开发-RecyclerView-AndroidStudio(二)点击删除数据
- Android开发-自定义View-AndroidStudio(三)扇形多级菜单
- Android开发-自定义View-AndroidStudio(四)简介动画
- Android开发-自定义View-AndroidStudio(二)遇到问题,附:ScrollView中文API
- Android开发-自定义View-AndroidStudio(十)仿ViewPager(1)