美文网首页Android开发经验谈Android技术知识Android开发
实现ListView的横向滑动可置顶或删除列表项

实现ListView的横向滑动可置顶或删除列表项

作者: 瑟闻风倾 | 来源:发表于2019-12-17 14:21 被阅读0次

    1. 自定义布局

    (1) 列表项布局 item_listview.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v7.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/title"
                android:textSize="20sp"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/content"
                android:textSize="16sp"/>
        </android.support.v7.widget.LinearLayoutCompat>
    </RelativeLayout>
    

    注意: item_listview.xml此处定义为RelativeLayout,和右侧布局添加到列表项(自定义ListView控件中)时使用RelativeLayout相对应。

    (2) 横向滑动列表项后显示的布局 item_listview_right.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button
            android:id="@+id/right_top"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#808080"
            android:padding="5dp"
            android:text="置顶"
            android:textColor="#FFFFFF"
            android:textSize="16sp">
        </Button>
        <Button
            android:id="@+id/right_delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FF0000"
            android:padding="5dp"
            android:text="删除"
            android:textColor="#FFFFFF"
            android:textSize="16sp">
        </Button>
    </LinearLayout>
    

    2. 自定义ListView控件

    创建MyListView类,继承自ListView并实现了OnTouchListener和OnGestureListener接口

    package comi.example.liy.view;
    
    import android.content.Context;
    import android.os.Build;
    import android.support.annotation.RequiresApi;
    import android.util.AttributeSet;
    import android.view.GestureDetector;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    
    import comi.example.liy.mytestdemo.R;
    
    /**
     * Created by liy on 2019-12-16 17:04
     */
    public class MyListView extends ListView implements View.OnTouchListener, GestureDetector.OnGestureListener {
    
        private GestureDetector mGestureDetector; // 手势动作探测器
        private View rightView; // 横向滑动列表项后显示
        private ViewGroup mItemLayout;// 列表项布局
        private int mSelectedItem;// 选择的列表项
        private boolean isRightViewShown;// 当前删除按钮是否显示出来了
    
        public MyListView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            mGestureDetector = new GestureDetector(getContext(),this);//创建手势监听器对象
            setOnTouchListener(this);//本控件的触摸事件
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (isRightViewShown) {
                hideRightView();
                return false;
            } else {
                return mGestureDetector.onTouchEvent(event);
            }
        }
    
        // 隐藏删除按钮
        public void hideRightView() {
            mItemLayout.removeView(rightView);
            rightView = null;
            isRightViewShown = false;
        }
    
        public boolean isRightViewShown() {
            return isRightViewShown;
        }
    
        /**
         * 删除事件的回调
         */
        public interface ClickCallback{
            void onLongPressed(int index);
            void onDeletePressed(int index);
            void onTopPressed(int index);
        }
        private ClickCallback callback;
    
        public void setCallback(ClickCallback callback) {
            this.callback = callback;
        }
    
        @Override
        public boolean onDown(MotionEvent e) {
            if (!isRightViewShown) {
                mSelectedItem = pointToPosition((int) e.getX(), (int) e.getY());
            }
            return false;
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
            //Toast.makeText(getContext(),"onShowPress",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            //Toast.makeText(getContext(),"onSingleTapUp",Toast.LENGTH_SHORT).show();
            return false;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            //Toast.makeText(getContext(),"滚动",Toast.LENGTH_SHORT).show();
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
            //Toast.makeText(getContext(),"长按",Toast.LENGTH_SHORT).show();
            callback.onLongPressed(mSelectedItem);
        }
    
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            // 如果右侧布局没有显示出来,并且x方向滑动的速度大于y方向的滑动速度
            if (!isRightViewShown && Math.abs(velocityX) > Math.abs(velocityY)) {
                rightView = LayoutInflater.from(getContext()).inflate(R.layout.item_listview_right,null);
                Button btnDelete = rightView.findViewById(R.id.right_delete);
                Button btnTop = rightView.findViewById(R.id.right_top);
                btnDelete.setOnClickListener(new OnClickListener() {
                      @Override
                      public void onClick(View v) {
                          mItemLayout.removeView(rightView);
                          rightView = null;
                          isRightViewShown = false;
                          callback.onDeletePressed(mSelectedItem);
                      }
                 });
                btnTop.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mItemLayout.removeView(rightView);
                        rightView = null;
                        isRightViewShown = false;
                        callback.onTopPressed(mSelectedItem);
                    }
                });
                mItemLayout = (ViewGroup) getChildAt(mSelectedItem - getFirstVisiblePosition());
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                params.addRule(RelativeLayout.CENTER_VERTICAL);
                mItemLayout.addView(rightView, params);
                isRightViewShown = true;
            }
            return false;
        }
    }
    
    

    注意:右侧布局添加到列表项使用了RelativeLayout来实现,列表项布局 item_listview.xml也应该定义为RelativeLayout,否则横向滑动时无法显示右侧布局(即置顶和删除按钮)。

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, >LayoutParams.WRAP_CONTENT);
    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    params.addRule(RelativeLayout.CENTER_VERTICAL);
    mItemLayout.addView(rightView, params);
    

    3. 使用自定义ListView

    (1) activity_listview2.xml

    布局中引入自定义的ListView

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <comi.example.liy.view.MyListView
            android:id="@+id/my_lv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        </comi.example.liy.view.MyListView>
    </LinearLayout>
    

    (2) ListViewTest2Activity.java

    Activity中自定义适配器,并对列表做初始化、设置列表项置顶删除事件的处理

    package comi.example.liy.mytestdemo;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    
    import comi.example.liy.view.MyListView;
    
    /**
     * Created by liy on 2019-12-17 9:38
     */
    public class ListViewTest2Activity extends AppCompatActivity {
        private MyListView customListView;
        private MyAdapter myAdapter;
        private ArrayList<NewsInfo> newsInfos = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_listview2);
    
            customListView = findViewById(R.id.my_lv);
    
            //myAdapter = new MyAdapter(this);
            newsInfos = getNewsInfos();
            myAdapter = new MyAdapter(this,newsInfos);
    
            customListView.setAdapter(myAdapter);
    
            customListView.setCallback(new MyListView.ClickCallback() {
                @Override
                public void onLongPressed(int index) {
                    Toast.makeText(ListViewTest2Activity.this,"长按无效哈,列表项横向滑动试试呢",Toast.LENGTH_SHORT).show();
                }
                @Override
                public void onDeletePressed(int index) {
                    newsInfos.remove(index);
                    myAdapter.notifyDataSetChanged();
                }
                @Override
                public void onTopPressed(int index) {
                    NewsInfo newsInfo = newsInfos.get(index);//保存当前位置的数据
                    newsInfos.remove(index);//列表中删除该条数据
                    newsInfos.add(0,newsInfo);//将该数据排在列表最前面
                    myAdapter.notifyDataSetChanged();
                }
    
            });
    
    
    
        }
    
        private ArrayList<NewsInfo> getNewsInfos(){
            ArrayList<NewsInfo> newsInfos = new ArrayList<>();
            newsInfos.add(new NewsInfo("标题1","信息内容1"));
            newsInfos.add(new NewsInfo("标题2","信息内容2"));
            newsInfos.add(new NewsInfo("标题3","信息内容3"));
            newsInfos.add(new NewsInfo("标题4","信息内容4"));
            newsInfos.add(new NewsInfo("标题5","信息内容5"));
            newsInfos.add(new NewsInfo("标题6","信息内容6"));
            newsInfos.add(new NewsInfo("标题7","信息内容7"));
            newsInfos.add(new NewsInfo("标题8","信息内容8"));
            newsInfos.add(new NewsInfo("标题9","信息内容9"));
            newsInfos.add(new NewsInfo("标题10","信息内容10"));
            return newsInfos;
        }
    
        @Override
        public void onBackPressed() {
            if (customListView.isRightViewShown()){
                customListView.hideRightView();
                return;
            }
            super.onBackPressed();
        }
    
        class MyAdapter extends BaseAdapter {
            private Context context;
            private ArrayList<NewsInfo> newsInfos = new ArrayList<>();
    
            public MyAdapter(Context context) {
                this.context = context;
                newsInfos = new NewsInfo().getNewsInfos();
            }
    
            public MyAdapter(Context context,ArrayList<NewsInfo> newsInfos) {
                this.context = context;
                this.newsInfos = newsInfos;
            }
    
            //计算数据资源的长度:有n条数据就会调用n次getView()方法来绘制Item,当数据长度很多时,ListView的recycleBin机制(内存回收机制)保证滑动时不会发生OOM(内存泄漏)
            @Override
            public int getCount() {
                if (newsInfos == null){
                    return 0;
                }
                return newsInfos.size();
            }
    
            @Override
            public Object getItem(int position) {
                return newsInfos.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            //绘制ListView的每个Item
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder viewHolder;
                if (convertView == null){
                    convertView = LayoutInflater.from(ListViewTest2Activity.this).inflate(R.layout.item_listview,null);
                    viewHolder = new ViewHolder();
                    viewHolder.title = convertView.findViewById(R.id.title);
                    viewHolder.content = convertView.findViewById(R.id.content);
                    convertView.setTag(viewHolder);
                }else {
                    viewHolder = (ViewHolder)convertView.getTag();
                }
                viewHolder.title.setText(newsInfos.get(position).getTitle());
                viewHolder.content.setText(newsInfos.get(position).getContent());
                return convertView;
            }
    
            class ViewHolder{
                private TextView title;
                private TextView content;
            }
        }
    
    }
    
    

    备注:测试用的实体类NewsInfo.java文件如下

    package comi.example.liy.mytestdemo;
    
    import java.util.ArrayList;
    
    /**
     * Created by liy on 2019-11-08 15:54
     */
    public class NewsInfo {
        private String title;
        private String content;
    
        public NewsInfo() {
    
        }
    
        public NewsInfo(String title, String content) {
            this.title = title;
            this.content = content;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        //创建测试数据
        public ArrayList<NewsInfo> getNewsInfos(){
            ArrayList<NewsInfo> newsInfos = new ArrayList<>();
            newsInfos.add(new NewsInfo("标题1","信息内容1"));
            newsInfos.add(new NewsInfo("标题2","信息内容2"));
            newsInfos.add(new NewsInfo("标题3","信息内容3"));
            newsInfos.add(new NewsInfo("标题4","信息内容4"));
            newsInfos.add(new NewsInfo("标题5","信息内容5"));
            newsInfos.add(new NewsInfo("标题6","信息内容6"));
            newsInfos.add(new NewsInfo("标题7","信息内容7"));
            newsInfos.add(new NewsInfo("标题8","信息内容8"));
            newsInfos.add(new NewsInfo("标题9","信息内容9"));
            newsInfos.add(new NewsInfo("标题10","信息内容10"));
            return newsInfos;
        }
    
    }
    
    

    4. 运行效果

    运行效果.png

    (1) 列表项置顶


    横向滑动-点击置顶.png
    置顶成功.png

    置顶:将集合中指定位置的元素重新排序放到首位。数据改变后注意通知适配器刷新,即调用myAdapter.notifyDataSetChanged(),否则页面显示不会改变。

     @Override
    public void onTopPressed(int index) {
          NewsInfo newsInfo = newsInfos.get(index);//保存当前位置的数据
          newsInfos.remove(index);//列表中删除该条数据
          newsInfos.add(0,newsInfo);//将该数据排在列表最前面
          myAdapter.notifyDataSetChanged();
    }
    

    (2) 列表项删除


    横向滑动-点击删除.png
    删除成功..png

    删除:将集合中指定位置的元素删除。数据改变后注意通知适配器刷新,即调用myAdapter.notifyDataSetChanged(),否则页面显示不会改变。

    @Override
     public void onDeletePressed(int index) {
           newsInfos.remove(index);
           myAdapter.notifyDataSetChanged();
    }
    

    拓展Android自定义View的实现

    相关文章

      网友评论

        本文标题:实现ListView的横向滑动可置顶或删除列表项

        本文链接:https://www.haomeiwen.com/subject/zjjdnctx.html