Android(安卓)---- 侧滑删除菜单的实现
16lz
2021-01-26
环境说明
操作系统:Win10IDE:Android Studio
实现效果
实现代码
一、布局文件
(一)item_content.xml【ListView的Item的内容】
<?xml version="1.0" encoding="utf-8"?>:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:text="Item1" android:textSize="25sp" android:gravity="center" android:textColor="@android:color/black"> >
显示效果
(二)item_menu.xml【Item的侧滑删除按钮】
<?xml version="1.0" encoding="utf-8"?>:android="http://schemas.android.com/apk/res/android" android:layout_width="70dp" android:layout_height="60dp" android:gravity="center" android:background="@android:color/holo_red_light" android:text="删除" android:textSize="25sp" android:textColor="#FFFFFFFF"> >
显示效果
(三)item_main.xml【一个完整Item】
SlideLayout为自定义Layout
<?xml version="1.0" encoding="utf-8"?>:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp"> :id="@+id/item_content" layout="@layout/item_content"/> :id="@+id/item_menu" layout="@layout/item_menu"/> >
显示效果
(三)activity_main.xml【包含一个ListView】
<?xml version="1.0" encoding="utf-8"?>:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> :id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="match_parent"/> >
二、Java代码
(一)、SlideLayout.java
package com.example.slidelayout;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;import androidx.annotation.NonNull;import androidx.annotation.Nullable;public class SlideLayout extends FrameLayout { private static final String TAG=SlideLayout.class.getSimpleName(); private View contentView; // 内容视图 private View menuView; // 菜单视图 private int contentWidth; // 内容视图的高度 private int contentHeight; // 内容视图的宽度 private int menuWidth; // 菜单视图的宽度 private int menuHeight; // 菜单视图的宽度 private Scroller scroller; // 专门用于处理滚动效果的工具类 private float downX; // 按下的x坐标 private float downY; private float endX; private float endY; // 当前的Y坐标,中间变化 private float startX; // 开始的x坐标,中间变化 /** * xml布局方式加载使用 * @param context * @param attrs */ public SlideLayout(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); scroller =new Scroller(context); } /** * XML布局被加载完后,就会回调onFinshInfalte这个方法,在这个方法中我们可以初始化控件和数据。 */ @Override protected void onFinishInflate() { super.onFinishInflate(); contentView = findViewById(R.id.item_content); menuView = findViewById(R.id.item_menu); } /** * 设置子视图的位置 * @param changed * @param left * @param top * @param right * @param bottom */ @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,menuHeight); } /** * 测量子视图的宽度和高度 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); contentHeight = contentView.getMeasuredHeight(); contentWidth = contentView.getMeasuredWidth(); menuHeight = menuView.getMeasuredHeight(); menuWidth = menuView.getMeasuredWidth(); } /** * 触摸事件 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: // 记录最初的x坐标 startX = event.getX(); downX = event.getX(); downY = event.getY(); break; case MotionEvent.ACTION_MOVE: endX = event.getX(); endY = event.getY(); // dx为横向发生的完整距离 float dx = Math.abs(endX - downX); if (dx > 0 ) { // 只要发生横向滑动,纵向禁止滑动 getParent().requestDisallowInterceptTouchEvent(true); } // 滑动距离 float dis = endX-startX; Log.e("onTouchEvent:", String.valueOf(dis)); // 向左滑为负值,通过下面一行代码转换至滑至的x坐标 dis = getScrollX()-dis; if (dis < 0){ // 坐标最小为0 dis = 0; }else if (dis > menuWidth){ // 最多向左滑menuWidth距离 dis = menuWidth; } scrollTo((int) dis,getScrollY()); // 更新开始x坐标 startX = event.getX(); break; case MotionEvent.ACTION_UP: // 如果滑出距离小于菜单宽度一半,菜单自动关闭 int totalX = getScrollX(); // 视图显示部分的左边缘 if (totalX < menuWidth/2){ closeMenu(); }else { openMenu(); } break; } return true; } /** * 拦截触摸事件 * @param event * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean isIntercept = false; // 最初为不拦截 switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = startX = event.getX(); try { if (onStateChangeListener == null){ throw new Exception("状态改变监听者未设置"); } onStateChangeListener.onDown(SlideLayout.this); // 关闭其他item }catch (Exception e){ e.printStackTrace(); } break; case MotionEvent.ACTION_MOVE: endX = event.getX(); float distance = Math.abs(endX - startX); if (distance > 0){ // 横向发生滑动,拦截事件 isIntercept = true; } break; } return isIntercept; } /** * 打开菜单 */ public void openMenu(){ int distance = menuWidth - getScrollX(); // 剩余未滑动距离 Log.e("openMenu:", String.valueOf(getScrollX())); scroller.startScroll(getScrollX(),getScrollY(),distance,0); // 滑动处理 invalidate(); // 重绘 try { if (onStateChangeListener == null){ throw new Exception("状态改变监听者未设置"); } onStateChangeListener.onOpen(SlideLayout.this); // 打开item为当前item }catch (Exception e){ e.printStackTrace(); } } /** * 关闭菜单 */ public void closeMenu(){ int distance = 0 - getScrollX(); Log.e("closeMenu:", String.valueOf(getScrollX())); scroller.startScroll(getScrollX(),getScrollY(),distance,0); invalidate(); try { if (onStateChangeListener == null){ throw new Exception("状态改变监听者未设置"); } onStateChangeListener.onClose(SlideLayout.this); }catch (Exception e){ e.printStackTrace(); } } @Override public void computeScroll() { super.computeScroll(); if (scroller.computeScrollOffset()){ // 滑动未结束 scrollTo(scroller.getCurrX(),scroller.getCurrY()); // 继续滑动到当前位置 invalidate(); } } /** * 监听菜单打开关闭 */ public interface OnStateChangeListener{ void onClose(SlideLayout layout); void onDown(SlideLayout layout); void onOpen(SlideLayout layout); } private OnStateChangeListener onStateChangeListener; public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) { this.onStateChangeListener = onStateChangeListener; }}
(二)、MyContent.java
package com.example.slidelayout;public class MyContent { private String name; public MyContent(String name){ this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
(三)、MainActivity.java
package com.example.slidelayout;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;public class MainActivity extends AppCompatActivity { private ListView listView; private ArrayList<MyContent> myContents; private SlideLayout slideLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setMyContents(); initView(); } /** * 设置数据 */ private void setMyContents(){ myContents = new ArrayList<>(); for (int i=1;i<100;++i){ MyContent myContent = new MyContent("Item"+i); myContents.add(myContent); } } /** * 初始化视图 */ private void initView(){ listView = findViewById(R.id.lv_main); listView.setAdapter(new MyAdapter()); // 设置适配器 } /** * 适配器 */ private class MyAdapter extends BaseAdapter { @Override public int getCount() { return myContents.size(); } @Override public Object getItem(int position) { return myContents.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null){ // 若不存在,则创建一个新的视图 convertView = View.inflate(MainActivity.this,R.layout.item_main,null); viewHolder = new ViewHolder(); viewHolder.item_content = convertView.findViewById(R.id.item_content); viewHolder.item_menu = convertView.findViewById(R.id.item_menu); convertView.setTag(viewHolder); }else { // 直接复用 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.item_content.setText(myContents.get(position).getName()); viewHolder.item_content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String info = myContents.get(position).getName(); Toast.makeText(MainActivity.this,info,Toast.LENGTH_SHORT).show(); } }); viewHolder.item_menu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SlideLayout slideLayout = (SlideLayout) v.getParent(); // 获取父亲视图 slideLayout.closeMenu(); // 关闭当前菜单 myContents.remove(position); // 移除 notifyDataSetChanged(); // 通知更变 } }); SlideLayout slideLayout = (SlideLayout) convertView; slideLayout.setOnStateChangeListener(new MyOnStateChangeListener()); // 设置监听者 return convertView; } } static class ViewHolder { TextView item_content; TextView item_menu; } private class MyOnStateChangeListener implements SlideLayout.OnStateChangeListener { @Override public void onClose(SlideLayout layout) { // 菜单关闭后,选中item为空 if (slideLayout == layout){ slideLayout = null; } } @Override public void onDown(SlideLayout layout) { if (slideLayout != null && slideLayout != layout) { // 当打开其他item的菜单时,关闭已打开的菜单 slideLayout.closeMenu(); } } @Override public void onOpen(SlideLayout layout) { if (slideLayout == null){ slideLayout = layout; } } }}
更多相关文章
- Android(安卓)UI(三)SlidingMenu实现滑动菜单(详细 官方)
- [置顶] ANDROID 返回,菜单和HOME键的监听
- Android(安卓)ViewPager用法
- Android屏蔽Home键、屏蔽下拉菜单最有效的办法(部分手机无效)
- 卫星式菜单
- android用户界面-组件Widget-网格视图GridView
- android 8.1Settings添加设置项
- android Preference视图的使用
- Android(安卓)View的scrollTo()、scrollBy() 和Scroller类总结