环境说明

操作系统: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;            }        }    }}

更多相关文章

  1. Android(安卓)UI(三)SlidingMenu实现滑动菜单(详细 官方)
  2. [置顶] ANDROID 返回,菜单和HOME键的监听
  3. Android(安卓)ViewPager用法
  4. Android屏蔽Home键、屏蔽下拉菜单最有效的办法(部分手机无效)
  5. 卫星式菜单
  6. android用户界面-组件Widget-网格视图GridView
  7. android 8.1Settings添加设置项
  8. android Preference视图的使用
  9. Android(安卓)View的scrollTo()、scrollBy() 和Scroller类总结

随机推荐

  1. 解决MySQL读写分离导致insert后select不
  2. mysql innodb的重要组件汇总
  3. 详解mysql持久化统计信息
  4. Go 和 Android(安卓)集成实战
  5. Android(安卓)之 Window、WindowManager
  6. Android深入浅出之Audio第三部分Audio Po
  7. android仿网易云音乐引导页、仿书旗小说F
  8. 范例解析:学习Android的IPC主板模式
  9. Android(安卓)2.3系统令人为之兴奋的十大
  10. 【Android(安卓)内存优化】Bitmap 内存缓