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();
}
网友评论