【Android studio】listview+swiplistview整合侧滑实现
前言
本博文主要是对listview+swiplistview整合侧滑实现的一个介绍,以及记录,方便后续使用时候可以直接加载。
listview+swiplistview 介绍
listview
ListView是Android中常用的一个控件,用于展示一个特定的数据集合,可以以列表的形式展示多个项。
ListView的特点:
- 列表项可以是文本、图片或者多种视图的组合。
- 列表项可以有不同的交互效果,例如点击、长按、滑动等。
- 列表项可以根据需要进行动态添加、删除、更新等操作。
- 列表可以支持滚动和分页。
ListView的使用:
- 在布局文件中添加ListView控件:
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- 在代码中初始化ListView,并设置适配器:
ListView listView = findViewById(R.id.listView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, dataList);
listView.setAdapter(adapter);
- 定义数据源dataList并添加数据:
ArrayList<String> dataList = new ArrayList<>();
dataList.add("Item 1");
dataList.add("Item 2");
dataList.add("Item 3");
- 可以通过监听器来响应用户的交互事件,例如点击某个列表项:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 处理点击事件
}
});
注意事项:
- ListView默认只能显示简单的文本列表项,如果需要显示复杂的自定义列表项,可以使用自定义的适配器。
- 当数据量很大时,使用ListView可能会导致性能问题,可以考虑使用RecyclerView来优化。
- 在滚动时,ListView会重复利用列表项的视图,所以在适配器中需要正确地重用视图,以提高效率。
- 可以通过设置分割线、空视图等来美化ListView的展示效果。
swiplistview
SwipListView是一个Android Studio库,它提供了一个可以滑动的ListView控件。它允许用户在ListView上进行左滑、右滑和长按等操作,从而实现更多的交互性操作。
使用SwipListView,你可以通过简单的配置实现各种操作,包括:
-
左滑功能:用户可以在ListView的每一行上向左滑动,从而显示出一个隐藏的视图或菜单。这个功能可以用于实现删除、归档或其他相关操作。
-
右滑功能:用户可以在ListView的每一行上向右滑动,从而显示出一个隐藏的视图或菜单。这个功能可以用于实现标记、收藏或其他相关操作。
-
长按功能:用户可以通过长按某一行来触发一个操作,比如显示更多的详细信息或弹出一个上下文菜单。
SwipListView提供了简单的API,使你可以轻松地集成它到你的Android应用程序中。你只需要在布局文件中添加SwipListView控件,然后在代码中配置相应的操作即可。
总的来说,SwipListView是一个非常有用的库,可以提供更多的交互性操作和用户体验。它可以帮助你实现更复杂和灵活的ListView布局和功能。
实现
FrontViewToMove
FrontViewToMove–工具类–顺序:TouchListener–控件本身的ontouch–activity的ontouch;
即传播的顺序是: 监听器—>view组件的回调方法—>Activity的回调方法了;(全)
public class FrontViewToMove {
private View frontView;// 所要滑动的视图
private int downX;// 手指按下时的x坐标
private boolean hasMoved = false;// 判断视图是否被移动
private int xToMove ;// 视图所要被移动的距离,单位px
private ListView listView;// 如果所需移动的视图为ListView或其子类的item项,传入视图容器,限制其上下滚动
/**
* @param frontView 所要滑动的视图
*/
public FrontViewToMove(View frontView) {
this.frontView = frontView;
moveListener();
}
/**
* @param frontView 所要滑动的视图
* @param xToMove 视图所要被移动的距离
*/
public FrontViewToMove(View frontView, int xToMove) {
this.frontView = frontView;
this.xToMove = xToMove;
moveListener();
}
/**
* @param frontView 所要滑动的视图
* @param listView 所要滑动的视图的容器
* @param xToMove 所要滑动的视图距离
*/
public FrontViewToMove(View frontView, ListView listView,int xToMove) {
this.frontView = frontView;
this.listView = listView;
this.xToMove =xToMove;
moveListener();
}
/**
* @param frontView 所要滑动的视图
* @param listView 所要滑动的视图的容器
*/
public FrontViewToMove(View frontView, ListView listView) {
this.frontView = frontView;
this.listView = listView;
this.xToMove = xToMove;
moveListener();
}
/**
* 设置frontView的OnTouch监听,使其产生滑动的动画效果
*/
/*侧滑三种情况都触发,左侧滑up最后hasMoved--true,右侧滑承接上一个最后hasMOVED--false;
垂直移动up没有触发,且全局变量judge没有用,类似直接返回了true,没有进行下面的动作*/
public void moveListener() {
frontView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
/*1 getAction:触摸动作的原始32位信息,包括事件的动作,触控点信息
2 getActionMasked:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
3 getActionIndex:触控点信息*/
switch (MotionEventCompat.getActionMasked(motionEvent)) {
case MotionEvent.ACTION_DOWN: {
downX = (int) motionEvent.getRawX();
if (hasMoved) {
downX = downX + xToMove;
//Log.v("dowm",downX+"");
} else {
view.onTouchEvent(motionEvent);// 当视图没有被移动,返回事件,使点击事件可用。
}
return true;
}
case MotionEvent.ACTION_UP: {
//手指移动的x距离,目前类默认是左移
float deltaX = motionEvent.getRawX() - downX;
boolean swap = false;
//先左后右移过程中,超过2边范围的极端情况才会有swap=true
if ((deltaX > -xToMove / 2 && hasMoved)
|| (deltaX < -xToMove && !hasMoved)) {
swap = true;
}
if (swap) {//特殊情况
if (!hasMoved) {
//表示超了左移如果超出了移动距离xToMove,则让控件移动
//设置hasMoved移动
generateRevealAnimate(frontView, -xToMove);
hasMoved = true;
} else {
//如果hasMoved移动了,但是位移小于xToMove / 2,则控件不动
//并设置hasMoved未移动
generateRevealAnimate(frontView, 0);
hasMoved = false;
}
} else {//正常情况
if (hasMoved) {
generateRevealAnimate(frontView, -xToMove);
} else {
generateRevealAnimate(frontView, 0);
}
}
break;
}
case MotionEvent.ACTION_MOVE: {
float deltaX = motionEvent.getRawX() - downX;
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
//ACTION_CANCEL:
//触摸某个控件,但是又不是在这个控件的区域上抬起(移动到别的地方了)
//比如当你的手指在屏幕上拖动一个listView或者一个ScrollView而不是去按上面的按钮时会触发这个事件
//motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT:
//高8位触控信息index,低8位具体动作信息,通过ACTION_POINTER_INDEX_SHIFT,即截取触控索引时所需的移位个数
cancelEvent.setAction(MotionEvent.ACTION_CANCEL
| (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
//左移距离大于10
if (deltaX < -10) {
view.onTouchEvent(cancelEvent);// 当滑动时清空该视图的点击事件
if (null != listView) {// 当视图滑动时限制listView的上下滚动
listView.requestDisallowInterceptTouchEvent(false);
listView.onTouchEvent(cancelEvent);
}
}
//综合:即实现移动过程中的动画效果
if (!(deltaX > 0 && !hasMoved)) {
setTranslationX(frontView, deltaX);
}
// Log.v("test_move1",hasMoved+"");
return true;
}
}
//Log.v("end","end");
//false是为了继续向控件或者是activity的ontouchevent传递,在此处即即onclick
return false;
}
});
}
/**
* @param view 所要移动的视图
* @param deltaX 最终移动的距离
*/
private void generateRevealAnimate(final View view, float deltaX) {
int moveTo = 0;
moveTo = (int) deltaX;
//Log.v("moveto",deltaX+"");
animate(view).translationX(moveTo).setDuration(10)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
}
}
DensityUtil–工具类(全)
public class DensityUtil {
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
CenterDetailSubAdapter1–适配器(关键内容全)
public class CenterDetailSubAdapter1 extends BaseExpandableListAdapter{
private Context mContext;
private List<String> mGroupEntityList;
private List<List<CenterDetailChildBean1>> mChildEntityList;
private List<CenterDetailChildBean1> dataList_1;
private ExpandableListView list_view_expand;
private String left_time_str="",apply_authority_str="";
private JSONObject json;
private AlertDialog.Builder delete_builder,LeftTime_builder,click_item_dia_builder,Apply_builder;
private int groupPosition_temp,childPosition_temp;
public CenterDetailSubAdapter1(Context context, ExpandableListView list_view_expand,List<String> groupEntityList, List<List<CenterDetailChildBean1>> childEntityList) {
this.mContext = context;
this.list_view_expand=list_view_expand;
this.mGroupEntityList = groupEntityList;
this.mChildEntityList = childEntityList;
}
@Override
public int getGroupCount() {
if (mGroupEntityList.size() > 0){
return mGroupEntityList.size();
}
return 0;
}
@Override
public int getChildrenCount(int groupPosition) {
if (mChildEntityList.get(groupPosition).size() > 0){
return mChildEntityList.get(groupPosition).size();
}
return 0;
// return 1;
}
@Override
public Object getGroup(int groupPosition) {
return mGroupEntityList.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mChildEntityList.get(groupPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
//分组和子选项是否持有稳定的ID, 就是说底层数据的改变会不会影响到它们
public boolean hasStableIds() {
return false;//改false
}
/**
*
* 获取显示指定组的视图对象
*
* @param groupPosition 组位置
* @param isExpanded 该组是展开状态还是伸缩状态,true=展开
* @param convertView 重用已有的视图对象
* @param parent 返回的视图对象始终依附于的视图组
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
CenterDetailSubAdapter1.GroupViewHolder groupViewHolder;
if(convertView==null){
groupViewHolder = new CenterDetailSubAdapter1.GroupViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_center_detail_lv_group, null);
groupViewHolder.groupName = (TextView) convertView.findViewById(R.id.group_name);
groupViewHolder.groupStatus2 = (ImageView) convertView.findViewById(R.id.group_status2);
convertView.setTag(groupViewHolder);
}else {
groupViewHolder = (CenterDetailSubAdapter1.GroupViewHolder) convertView.getTag();
}
groupViewHolder.groupName.setText(mGroupEntityList.get(groupPosition));
//如果是展开状态
if (isExpanded) {
Glide.with(mContext).load( R.mipmap.expended).into(groupViewHolder.groupStatus2);
}else{
Glide.with(mContext).load(R.mipmap.unexpended).into(groupViewHolder.groupStatus2);
}
return convertView;
}
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final CenterDetailSubAdapter1.ChildViewHolder childViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_index_adapter1, parent, false);//注意写法!!!
childViewHolder = new CenterDetailSubAdapter1.ChildViewHolder();
childViewHolder.item_lin=(LinearLayout)convertView.findViewById(R.id.index_item);
childViewHolder.state_img=(ImageView)convertView.findViewById(R.id.index_list_img);
childViewHolder.listName_tv=(AppCompatTextView)convertView.findViewById(R.id.tv_index_list_name);
childViewHolder.listbelong_tv=(AppCompatTextView)convertView.findViewById(R.id.tv_index_list_belong);
childViewHolder.listTime_tv=(AppCompatTextView)convertView.findViewById(R.id.tv_index_list_time);
childViewHolder.item_rl_bg=(LinearLayout)convertView.findViewById(R.id.item_rl_bg);
childViewHolder.btn_delete=(Button)convertView.findViewById(R.id.btn_delete);
childViewHolder.btn_arthority=(Button)convertView.findViewById(R.id.btn_arthority);
childViewHolder.btn_left=(Button)convertView.findViewById(R.id.btn_left_timme);
childViewHolder.id_back=(LinearLayout)convertView.findViewById(R.id.id_back);
childViewHolder.listView_frame=(FrameLayout)convertView.findViewById(R.id.listView_fram);
convertView.setTag(childViewHolder);
} else {
childViewHolder = (CenterDetailSubAdapter1.ChildViewHolder) convertView.getTag();
}
CenterDetailChildBean1 bean= mChildEntityList.get(groupPosition).get(childPosition);
if(bean.getModule_name()==null)
{
childViewHolder.listName_tv.setText("未命名设备");
}
else
{
childViewHolder.listName_tv.setText(bean.getModule_name());
}
String temp_belon=bean.getBelong_to();
childViewHolder.listbelong_tv.setText(temp_belon);
childViewHolder.state_img.setImageResource(R.mipmap.lock_icon);
childViewHolder.item_lin.setBackgroundResource(R.drawable.indexitem_normal);
childViewHolder.item_rl_bg.setOnClickListener(new View.OnClickListener() {
//因为重写ontouch事件使onChildClickListener失效,需要设置次监听来补救
public void onClick(View v) {
// TODO Auto-generated method stub
animate(childViewHolder.item_rl_bg).translationX(0).setDuration(10)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
item_onclick(groupPosition,childPosition);
// Toast.makeText(mContext, "条目按下", Toast.LENGTH_SHORT)
// .show();
// Log.v("点击事件:",childViewHolder.listName_tv.getText().toString());
}
});
//解决item垂直滑不回去的bug
setTranslationX(childViewHolder.item_rl_bg, 0);
int px=DensityUtil.dip2px(mContext,160);
new FrontViewToMove(childViewHolder.item_rl_bg,list_view_expand,px);
//setTranslationX(childViewHolder.item_rl_bg, 0);
// animate(childViewHolder.item_rl_bg).translationX(0).setDuration(2)
// .setListener(new AnimatorListenerAdapter() {
// @Override
// public void onAnimationEnd(Animator animation) {
//
// }
// });
//Log.v("a","shifou");
//关键语句,使用自己写的类来对frontView的ontouch事件复写,实现视图滑动效果
childViewHolder.btn_delete.setOnClickListener(new View.OnClickListener() {
// 为button绑定事件,可以用此按钮来实现删除事件
@Override
public void onClick(View v) {
if(delete_builder==null){
delete_builder= new AlertDialog.Builder(mContext);
delete_builder.setTitle("提示")
.setMessage("是否确认解除绑定该设备")
.setPositiveButton("确定", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
groupPosition_temp =groupPosition;
childPosition_temp=childPosition;
delete_border(groupPosition,childPosition);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
}
});
}
delete_builder.show();
// Toast.makeText(mContext, "按钮按下", Toast.LENGTH_SHORT)
// .show();
// Log.v("按钮事件:",childViewHolder.listName_tv.getText().toString());
animate(childViewHolder.item_rl_bg).translationX(0).setDuration(10)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
}
});
childViewHolder.btn_arthority.setOnClickListener(new View.OnClickListener() {
// 为button绑定事件,可以用此按钮来实现删除事件
@Override
public void onClick(View v) {
apply_authority(groupPosition,childPosition);
animate(childViewHolder.item_rl_bg).translationX(0).setDuration(10)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
}
});
childViewHolder.btn_left.setOnClickListener(new View.OnClickListener() {
// 为button绑定事件,可以用此按钮来实现删除事件
@Override
public void onClick(View v) {
check_left_time(groupPosition,childPosition);
animate(childViewHolder.item_rl_bg).translationX(0).setDuration(10)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
}
});
return convertView;
}
//item点击
public void item_onclick(int groupPosition,int childPosition){
}
//删除绑定
public void delete_border(int groupPosition,int childPosition)
{
}
//申请运维权限
private void apply_authority(int groupPosition,int childPosition)
{
}
//查询剩余日期
private void check_left_time(int groupPosition,int childPosition)
{
}
//指定位置上的子元素是否可选中
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public static class GroupViewHolder {
TextView groupName;
ImageView groupStatus2;
}
public static class ChildViewHolder {
TextView listName_tv;
TextView listbelong_tv;
ImageView state_img;
TextView listTime_tv;
LinearLayout item_lin;
LinearLayout item_rl_bg;
LinearLayout id_back;
Button btn_delete;
Button btn_arthority;
Button btn_left;
FrameLayout listView_frame;
}
}
fragment_index–xml(关键内容全)
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/background">
<ExpandableListView
android:id="@+id/index_expandableList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:childDivider="@drawable/separator"
android:dividerHeight="10dp"
android:divider="@drawable/separator"
/>
</LinearLayout>
item_center_detail_lv_group–xml(全)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:layout_width="match_parent"
android:background="@color/background"
android:layout_height="48dp"
android:layout_marginTop="5dp">
<TextView
android:id="@+id/group_name"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:gravity="center"
android:text="000"
android:textAlignment="viewStart"
android:textColor="#000000"
android:textSize="15sp" />
<ImageView
android:id="@+id/group_status2"
android:src="@mipmap/expended"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginRight="20dp" />
</LinearLayout>
item_index_adapter1–xml(全)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/listView_fram">
<LinearLayout
android:id="@+id/id_back"
android:layout_width="fill_parent"
android:layout_height="158dp"
android:gravity="right"
android:layout_marginRight="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/btn_delete"
android:layout_width="50dp"
android:layout_height="match_parent"
android:text="删除"
android:background="@color/apply_delete"
/>
<Button
android:id="@+id/btn_arthority"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="@color/apply_arthority"
android:text="申请运维权限"
/>
<Button
android:id="@+id/btn_left_timme"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="@color/apply_left"
android:text="剩余查看时间"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="158dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/indexitem_normal"
android:orientation="vertical"
android:id="@+id/item_rl_bg"
>
<LinearLayout
android:id="@+id/index_item"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/indexitem_normal"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/index_list_img"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="5dp"
android:src="@mipmap/lianjie" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:orientation="vertical">
<android.support.v7.widget.AppCompatTextView
android:layout_marginTop="5dp"
android:layout_marginBottom="1dp"
android:id="@+id/tv_index_list_belong"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginStart="5dp"
android:gravity="center_vertical"
android:textColor="#000000"
android:textStyle="bold"
android:maxLines="2"
android:textSize="16sp"
/>
/>
<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_index_list_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:textColor="@color/gray"
android:maxLines="1"
android:textSize="13sp"
/>
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="2dp"
android:background="@color/qianray" />
<LinearLayout
android:id="@+id/index_item1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/indexitem_normal"
android:orientation="vertical">
<android.support.v7.widget.AppCompatTextView
android:layout_marginTop="10dp"
android:layout_marginBottom="3dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:gravity="left"
android:textColor="@color/gray"
android:textSize="16sp" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_index_list_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:gravity="left"
android:maxLines="2"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
xml图片