美文网首页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