Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说Android精美自定义多选控件_多选Spinner_MultiSpinner_拿来即用,希望能够帮助你!!!。
1.首先去定义该控件:MPopListView
package com.maddox.mmrrr1;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Maddox
* 2021-11-30
*/
public class MPopListView extends LinearLayout {
private Context mContext;
private MFlowLayout flowLayout;
private ImageView iv_arrow;
private List<DataModel> allDatas;
public MPopListView(Context context) {
this(context, null);
}
public MPopListView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MPopListView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
LayoutInflater.from(mContext).inflate(R.layout.layout_pop_list_view, this, true);
initView();
}
private void initView() {
allDatas = new ArrayList<>();
flowLayout = findViewById(R.id.mflowlayout);
iv_arrow = findViewById(R.id.iv_arrow);
iv_arrow.setOnClickListener(v -> {
showPopWindow(this);
});
flowLayout.setOnItemClickListener(new MFlowLayout.OnItemClickListener() {
@Override
public void onItemClick(View itemView, int position) {
String removeName = flowLayout.removeItem(position);
for (DataModel allData : allDatas) {
if (allData.getText().equals(removeName)) {
allData.setSelected(false);
}
}
}
});
}
/**
* 外部调用
* 初始化数据
* 设置所有待展示的数据
*
* @param list 展示的数据
*/
public void setInitList(List<DataModel> list) {
allDatas.clear();
allDatas.addAll(list);
}
/**
* 外部调用
* 返回已选择的所有数据
*
* @return
*/
public List<DataModel> getSelectedList() {
List<DataModel> selectedList = new ArrayList<>();
for (DataModel data : allDatas) {
if (data.getSelected()) {
selectedList.add(data);
}
}
return selectedList;
}
/**
* 外部调用
* 设置展示的子条目文本颜色
*
* @param color 颜色值
*/
public void setItemTextColor(int color) {
flowLayout.setItemTextColor(color);
}
/**
* 外部调用
* 设置展示的子条目背景颜色
*
* @param drawable 自定义的Drawable类型
*/
public void setItemBackgroundDrawable(Drawable drawable) {
flowLayout.setItemBackgroundDrawable(drawable);
}
/**
* 外部调用
* 设置展示的子条目文本右侧小图标,默认是x
*
* @param imgRes 图片资源id
*/
public void setItemTextIcon(int imgRes) {
flowLayout.setItemTextIcon(imgRes);
}
/**
* 外部调用
* 设置调出弹窗的图片
*
* @param imgRes 图片资源
*/
public void setArrowImage(int imgRes) {
iv_arrow.setImageResource(imgRes);
}
private void setSelectDataList(List<DataModel> list) {
flowLayout.setData(list);
//更新所有数据中已选中的状态
for (DataModel model : list) {
if (allDatas.contains(model)) {
int index = allDatas.indexOf(model);
allDatas.get(index).setSelected(model.getSelected());
}
}
}
private void showPopWindow(MPopListView popListView) {
View contentView = LayoutInflater.from(mContext).inflate(R.layout.layout_pop_list_view_fly_content, null, false);
GridView gridView = contentView.findViewById(R.id.fly_grid_view);
TextView cancleBtn = contentView.findViewById(R.id.tv_dialog_cancle);
TextView confirmBtn = contentView.findViewById(R.id.tv_dialog_confirm);
ListItemAdapter itemAdapter = new ListItemAdapter(mContext, allDatas, R.layout.layout_pop_list_view_fly_content_item);
gridView.setAdapter(itemAdapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(mContext, allDatas.get(position).getText(), Toast.LENGTH_SHORT).show();
DataModel item = itemAdapter.getItem(position);
item.setSelected(!item.getSelected());
itemAdapter.notifyDataSetChanged();
}
});
AlertDialog alertDialog = new AlertDialog.Builder(mContext)
.setView(contentView)
.create();
cancleBtn.setOnClickListener(v -> {
if (alertDialog != null && alertDialog.isShowing()) {
alertDialog.dismiss();
}
});
confirmBtn.setOnClickListener(v -> {
if (alertDialog != null && alertDialog.isShowing()) {
alertDialog.dismiss();
//获取已选择的
popListView.setSelectDataList(itemAdapter.getSelectedList());
}
});
alertDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
WindowManager.LayoutParams lp = alertDialog.getWindow().getAttributes();
lp.width = LayoutParams.WRAP_CONTENT;
lp.height = LayoutParams.WRAP_CONTENT;
alertDialog.getWindow().setAttributes(lp);
alertDialog.show();
}
private class ListItemAdapter extends CommonAdapter<DataModel> {
public ListItemAdapter(Context mContext, List<DataModel> datas, int layoutId) {
super(mContext, datas, layoutId);
}
@Override
public void bindView(ViewHolder holder, DataModel dataModel, int position) {
holder.setText(R.id.item_text, dataModel.getText());
CheckBox checkBox = holder.getView(R.id.item_checkbox);
if (dataModel.getSelected()) {
checkBox.setChecked(true);
} else {
checkBox.setChecked(false);
}
}
public List<DataModel> getSelectedList() {
List<DataModel> datas = getDatas();
List<DataModel> haveChoose = new ArrayList<>();
for (DataModel data : datas) {
if (data.getSelected()) {
haveChoose.add(data);
}
}
return haveChoose;
}
}
}
2.里面用到的类:
package com.maddox.mmrrr1;
import android.app.ActionBar;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 流式布局
*
* @author Maddox
*/
public class MFlowLayout extends ViewGroup {
private Context mContext;
private int textColor = Color.WHITE;//默认展示的文本颜色
private Drawable textDrawable;//展示的文本背景色
//记录所有行的View列表
private List<List<View>> mViews = new ArrayList<>();
//记录所有行的各自最大高度
private List<Integer> mLineHeight = new ArrayList<>();
//记录当前绘制的实体数据
private List<DataModel> itemList = new ArrayList<>();
private int textIcon;//文本右侧小图片
public MFlowLayout(Context context) {
this(context, null);
}
public MFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
}
public String removeItem(int position) {
String name = itemList.get(position).getText();
itemList.remove(position);
List<DataModel> newList = new ArrayList<>();
newList.addAll(itemList);
setData(newList);
return name;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//当前布局的最大宽度和高度
int width = 0;
int height = 0;
//每一行子view的宽高
int lineWidth = 0;
int lineHeight = 0;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
//获取每个子View的宽度
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
//获取每个子View的高度
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
//如果当前子View与当前行的已使用宽度超出了父布局的宽度大小,则进入下一行
if (lineWidth + childWidth > widthSize - getPaddingLeft() - getPaddingRight()) {
//超出一行,先记录当前行的宽度,再去新建一行
width = Math.max(width, lineWidth);
//新的一行宽度等于当前子View的宽度
lineWidth = childWidth;
//记录行总高度
height += lineHeight;
//记录新一行的高度
lineHeight = childHeight;
} else {
//如果没有换行,则累加当前子View的宽度到当前行宽度
lineWidth += childWidth;
//得到行子View的最大行高度
lineHeight = Math.max(lineHeight, childHeight);
}
//处理最后一个子View的情况
if (i == count - 1) {
width = Math.max(lineWidth, width);
height += lineHeight;
}
}
//当父布局的宽高为具体值时,就使用设置的具体值,否则使用子View的总体宽高
int resultW = widthMode == MeasureSpec.EXACTLY ? widthSize : width + getPaddingLeft() + getPaddingRight();
int resultH = heightMode == MeasureSpec.EXACTLY ? heightSize : height + getPaddingTop() + getPaddingBottom();
//设置父布局的大小
setMeasuredDimension(resultW, resultH);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mViews.clear();
mLineHeight.clear();
//获取当前ViewGroup的宽度
int width = getWidth();
int lineWidth = 0;
int lingHeight = 0;
//记录当前行的View
List<View> lineViews = new ArrayList<>();
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight()) {
mLineHeight.add(lingHeight);
mViews.add(lineViews);
lineWidth = 0;
lingHeight = childHeight + lp.topMargin + lp.bottomMargin;
lineViews = new ArrayList<>();
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lingHeight = Math.max(lingHeight, childHeight + lp.topMargin + lp.bottomMargin);
lineViews.add(child);
}
//记录每行高度,为后面设置子View单独top做准备,比如 gravity
mLineHeight.add(lingHeight);
mViews.add(lineViews);
int left = getPaddingLeft();
int top = getPaddingTop();
int lineCount = mViews.size();
for (int i = 0; i < lineCount; i++) {
lineViews = mViews.get(i);
lingHeight = mLineHeight.get(i);
int lineViewCount = lineViews.size();
for (int j = 0; j < lineViewCount; j++) {
View child = lineViews.get(j);
if (child.getVisibility() == GONE) {
continue;
}
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
int cLeft = left + lp.leftMargin;
int cTop = top + lp.topMargin;
int cRight = child.getMeasuredWidth() + cLeft;
int cBottom = cTop + child.getMeasuredHeight();
child.layout(cLeft, cTop, cRight, cBottom);
left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
}
left = 0;
top += lingHeight;
}
}
/**
* 设置填充数据
*
* @param data
*/
public void setData(List<DataModel> data) {
removeAllViews();
if (data == null || data.size() <= 0) {
return;
}
itemList.clear();
itemList.addAll(data);
MarginLayoutParams lp = new MarginLayoutParams(LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT);
lp.leftMargin = 5;
lp.rightMargin = 5;
lp.topMargin = 5;
lp.bottomMargin = 5;
//初始化布局加载器
for (int i = 0; i < data.size(); i++) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.layout_flow_item, null, false);
TextView itemText = itemView.findViewById(R.id.tv_item_name);
ImageView itemIcon = itemView.findViewById(R.id.iv_item_icon);
itemText.setText(data.get(i).getText());
itemText.setTextColor(textColor);
if (textDrawable != null) {
itemView.setBackground(textDrawable);
}
if (textIcon != 0) {
itemIcon.setImageResource(textIcon);
}
addView(itemView, lp);
}
//因为是新创建的View,需要重新加载监听器
if (clickListener != null) {
setOnItemClickListener(clickListener);
}
}
private int randomColor() {
Random random = new Random();
return Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
private OnItemClickListener clickListener;
/**
* 设置点击事件
*
* @param clickListener 点击回调
*/
public void setOnItemClickListener(OnItemClickListener clickListener) {
if (clickListener == null)
return;
this.clickListener = clickListener;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
int index = i;
child.setOnClickListener(v -> {
this.clickListener.onItemClick(child, index);
});
}
}
public List<DataModel> getItemList() {
return itemList;
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
public void setItemTextColor(int color) {
textColor = color;
}
public void setItemBackgroundDrawable(Drawable drawable) {
textDrawable = drawable;
}
public void setItemTextIcon(int imgRes) {
textIcon = imgRes;
}
public static interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
}
3.然后上面这个类中用到的xml layout_flow_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_flow_item"
android:padding="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_item_name"
android:layout_width="wrap_content"
android:textSize="16dp"
android:layout_height="wrap_content"
android:clickable="true"
android:textColor="#fff"
tools:text="北京市" />
<ImageView
android:id="@+id/iv_item_icon"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
android:src="@mipmap/icon_item_close"
/>
</LinearLayout>
4.然后最上面那个自定义工具类中用到的xml文件 layout_pop_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/selector_stroke_theme"
android:padding="10dp"
android:orientation="horizontal">
<com.maddox.mmrrr1.MFlowLayout
android:id="@+id/mflowlayout"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/iv_arrow"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="10dp"
android:src="@mipmap/icon_select_list" />
</LinearLayout>
5.然后就是上面xml文件中用到的小图片
icon_select_list
这个图标仅仅是个案例,可以自己去找心仪的.
6.然后最上面控件中用到的xml文件
layout_pop_list_view_fly_content.xml
package com.maddox.mmrrr1;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Maddox
* 2021-11-30
*/
public class MPopListView extends LinearLayout {
private Context mContext;
private MFlowLayout flowLayout;
private ImageView iv_arrow;
private List<DataModel> allDatas;
public MPopListView(Context context) {
this(context, null);
}
public MPopListView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MPopListView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
LayoutInflater.from(mContext).inflate(R.layout.layout_pop_list_view, this, true);
initView();
}
private void initView() {
allDatas = new ArrayList<>();
flowLayout = findViewById(R.id.mflowlayout);
iv_arrow = findViewById(R.id.iv_arrow);
iv_arrow.setOnClickListener(v -> {
showPopWindow(this);
});
flowLayout.setOnItemClickListener(new MFlowLayout.OnItemClickListener() {
@Override
public void onItemClick(View itemView, int position) {
String removeName = flowLayout.removeItem(position);
for (DataModel allData : allDatas) {
if (allData.getText().equals(removeName)) {
allData.setSelected(false);
}
}
}
});
}
/**
* 外部调用
* 初始化数据
* 设置所有待展示的数据
*
* @param list 展示的数据
*/
public void setInitList(List<DataModel> list) {
allDatas.clear();
allDatas.addAll(list);
}
/**
* 外部调用
* 返回已选择的所有数据
*
* @return
*/
public List<DataModel> getSelectedList() {
List<DataModel> selectedList = new ArrayList<>();
for (DataModel data : allDatas) {
if (data.getSelected()) {
selectedList.add(data);
}
}
return selectedList;
}
/**
* 外部调用
* 设置展示的子条目文本颜色
*
* @param color 颜色值
*/
public void setItemTextColor(int color) {
flowLayout.setItemTextColor(color);
}
/**
* 外部调用
* 设置展示的子条目背景颜色
*
* @param drawable 自定义的Drawable类型
*/
public void setItemBackgroundDrawable(Drawable drawable) {
flowLayout.setItemBackgroundDrawable(drawable);
}
/**
* 外部调用
* 设置展示的子条目文本右侧小图标,默认是x
*
* @param imgRes 图片资源id
*/
public void setItemTextIcon(int imgRes) {
flowLayout.setItemTextIcon(imgRes);
}
/**
* 外部调用
* 设置调出弹窗的图片
*
* @param imgRes 图片资源
*/
public void setArrowImage(int imgRes) {
iv_arrow.setImageResource(imgRes);
}
private void setSelectDataList(List<DataModel> list) {
flowLayout.setData(list);
//更新所有数据中已选中的状态
for (DataModel model : list) {
if (allDatas.contains(model)) {
int index = allDatas.indexOf(model);
allDatas.get(index).setSelected(model.getSelected());
}
}
}
private void showPopWindow(MPopListView popListView) {
View contentView = LayoutInflater.from(mContext).inflate(R.layout.layout_pop_list_view_fly_content, null, false);
GridView gridView = contentView.findViewById(R.id.fly_grid_view);
TextView cancleBtn = contentView.findViewById(R.id.tv_dialog_cancle);
TextView confirmBtn = contentView.findViewById(R.id.tv_dialog_confirm);
ListItemAdapter itemAdapter = new ListItemAdapter(mContext, allDatas, R.layout.layout_pop_list_view_fly_content_item);
gridView.setAdapter(itemAdapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(mContext, allDatas.get(position).getText(), Toast.LENGTH_SHORT).show();
DataModel item = itemAdapter.getItem(position);
item.setSelected(!item.getSelected());
itemAdapter.notifyDataSetChanged();
}
});
AlertDialog alertDialog = new AlertDialog.Builder(mContext)
.setView(contentView)
.create();
cancleBtn.setOnClickListener(v -> {
if (alertDialog != null && alertDialog.isShowing()) {
alertDialog.dismiss();
}
});
confirmBtn.setOnClickListener(v -> {
if (alertDialog != null && alertDialog.isShowing()) {
alertDialog.dismiss();
//获取已选择的
popListView.setSelectDataList(itemAdapter.getSelectedList());
}
});
alertDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
WindowManager.LayoutParams lp = alertDialog.getWindow().getAttributes();
lp.width = LayoutParams.WRAP_CONTENT;
lp.height = LayoutParams.WRAP_CONTENT;
alertDialog.getWindow().setAttributes(lp);
alertDialog.show();
}
private class ListItemAdapter extends CommonAdapter<DataModel> {
public ListItemAdapter(Context mContext, List<DataModel> datas, int layoutId) {
super(mContext, datas, layoutId);
}
@Override
public void bindView(ViewHolder holder, DataModel dataModel, int position) {
holder.setText(R.id.item_text, dataModel.getText());
CheckBox checkBox = holder.getView(R.id.item_checkbox);
if (dataModel.getSelected()) {
checkBox.setChecked(true);
} else {
checkBox.setChecked(false);
}
}
public List<DataModel> getSelectedList() {
List<DataModel> datas = getDatas();
List<DataModel> haveChoose = new ArrayList<>();
for (DataModel data : datas) {
if (data.getSelected()) {
haveChoose.add(data);
}
}
return haveChoose;
}
}
}
7.上面xml中用到的xml shape_corner_white.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="15dp" />
<solid android:color="@android:color/white" />
</shape>
8.最上面类中,用到的xml文件layout_pop_list_view_fly_content_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:gravity="center_vertical"
android:orientation="horizontal">
<CheckBox
android:id="@+id/item_checkbox"
android:layout_width="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
tools:text="选中的条目内容"
android:textColor="#000"
android:textSize="17dp"
/>
</LinearLayout>
9.上面的 layout_pop_list_view_fly_content.xml 文件中用到的xml文件 selector_tv_bg1.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
<solid android:color="#f3f7f8"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
<solid android:color="#884176AC"/>
</shape>
</item>
</selector>
10.然后layout_pop_list_view.xml文件中用到的xml文件:selector_stroke_theme.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="5dp" />
<stroke android:width="2dp" android:color="#369484"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="5dp" />
<stroke android:width="2dp" android:color="#26C6DA"/>
</shape>
</item>
</selector>
11.然后,我们继续看,用到的放数据的实体类:
DataModel.java 接口
package com.maddox.mmrrr1;
/**
* 抽象出的数据类接口,以便列表用于展现数据文本
* 子类必须重写equals 和 hashcode方法
* 子类必须重写equals 和 hashcode方法
*/
public interface DataModel {
//数据用于展示的文本
public String getText();
//获取选中状态
public boolean getSelected();
//设置选中状态
public void setSelected(boolean selected);
}
12.然后
DemoModel.java 实现接口的实体类
package com.maddox.mmrrr1;
import java.util.Objects;
/**
* @author Maddox
* 2021-11-30
* 展示文本的实体实现 示例
* 必须重写equals 和 hashcode方法
* 必须重写equals 和 hashcode方法
* 必须重写equals 和 hashcode方法
* 必须重写equals 和 hashcode方法
*/
public class DemoModel implements DataModel {
public int id;//数据id
public String content;//数据内容
public boolean selected;//数据是否选中
public DemoModel() {
}
public DemoModel(int id, String content, boolean selected) {
this.id = id;
this.content = content;
this.selected = selected;
}
@Override
public String getText() {
return content;
}
@Override
public boolean getSelected() {
return selected;
}
@Override
public void setSelected(boolean selected) {
this.selected = selected;
}
@Override
public String toString() {
return "DemoModel{" +
"id=" + id +
", content='" + content + '\'' +
", selected=" + selected +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DemoModel demoModel = (DemoModel) o;
return id == demoModel.id && Objects.equals(content, demoModel.content);
}
@Override
public int hashCode() {
return Objects.hash(id, content);
}
}
13.然后再去看适配器:
package com.maddox.mmrrr1;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Maddox on 2017/11/15.
* 通用数据适配器 Listview gridview
*/
public abstract class CommonAdapter<T> extends BaseAdapter {
/**
* 数据源
*/
private List<T> datas = new ArrayList<>();
private Context mContext;
private int layoutId;//布局id
public CommonAdapter(Context mContext, List<T> datas, int layoutId) {
this.mContext = mContext;
this.layoutId = layoutId;
if (datas != null)
this.datas.addAll(datas);
}
@Override
public int getCount() {
return datas.size();
}
@Override
public T getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public List<T> getDatas() {
return datas;
}
/**
* 添加一条数据
*
* @param t 数据
*/
public void addOneData(T t) {
datas.add(t);
notifyDataSetChanged();
}
public void addAll(List<T> das) {
if (das != null) {
datas.addAll(das);
notifyDataSetChanged();
}
}
/**
* 添加数据到指定位置
*
* @param t 数据
* @param index 位置下标
*/
public void addOneData(T t, int index) {
datas.add(index, t);
notifyDataSetChanged();
}
public void clearData() {
datas.clear();
notifyDataSetChanged();
}
/**
* 判断已有数据中是否包含t
*
* @param t
* @return
*/
public boolean contains(T t) {
return datas.contains(t);
}
/**
* 移除一条数据
*
* @param t
*/
public void removeOneData(T t) {
datas.remove(t);
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//给每个条目绑定ViewHolder
ViewHolder viewHolder = ViewHolder.bind(mContext, convertView, parent, layoutId, position);
//把绑定结果反馈给调用适配器的人
bindView(viewHolder, getItem(position), position);
return viewHolder.getItemView();
}
/**
* 把ViewHolder和对应的数据示例抽象给使用者去实现具体操作
*
* @param holder
* @param t 数据
*/
public abstract void bindView(ViewHolder holder, T t, int position);
public static class ViewHolder {
private Context context;
private SparseArray<View> mViews;//缓存每个item布局中的控件
private View itemView;//记录一条item布局
private int position;//记录当前item的位置
private ViewHolder(Context context, ViewGroup parent, int layoutId) {
//初始化
this.context = context;
this.mViews = new SparseArray<>();
View convertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
convertView.setTag(this);
this.itemView = convertView;
}
/**
* 绑定当前itemView与ViewHolder
*
* @param context
* @param convertView 条目布局
* @param parent 条目view的ViewGroup
* @param layoutId 布局资源id
* @param position 布局位置
* @return
*/
public static ViewHolder bind(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder(context, parent, layoutId);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.position = position;
return holder;
}
/**
* 根据控件的id获取该控件
*
* @param viewId
* @param <T>
* @return
*/
public <T extends View> T getView(int viewId) {
T t = (T) mViews.get(viewId);
if (t == null) {
t = itemView.findViewById(viewId);
mViews.put(viewId, t);
}
return t;
}
/**
* 获取当前布局
*
* @return
*/
public View getItemView() {
return itemView;
}
/**
* 获取当前布局位置
*
* @return
*/
public int getPosition() {
return position;
}
/**
* 给指定id的控件设置文本
*
* @param tvId 控件id
* @param content 文本内容
* @return
*/
public ViewHolder setText(int tvId, CharSequence content) {
View tvView = getView(tvId);
if (tvView instanceof TextView) {
((TextView) tvView).setText(content);
}
return this;
}
public ViewHolder setTextColor(int tvId, int color) {
View tvView = getView(tvId);
if (tvView instanceof TextView) {
((TextView) tvView).setTextColor(color);
}
return this;
}
/**
* 给指定id的控件设置图片或者背景
*
* @param ivId 控件id
* @param imgResid 图片资源id
* @return
*/
public ViewHolder setImageResource(int ivId, int imgResid) {
View imageView = getView(ivId);
if (imageView instanceof ImageView) {
((ImageView) imageView).setImageResource(imgResid);
} else {
imageView.setBackgroundResource(imgResid);
}
return this;
}
/**
* 给指定id的控件设置图片或者背景
*
* @param ivId 控件id
* @param bitmap bitmap图片
* @return
*/
public ViewHolder setImageBitmap(int ivId, Bitmap bitmap) {
View imageView = getView(ivId);
if (imageView instanceof ImageView) {
((ImageView) imageView).setImageBitmap(bitmap);
}
return this;
}
/**
* 给指定id的控件设置点击事件
*
* @param viewId 控件id
* @param clickListener 监听器
* @return
*/
public ViewHolder setOnClickListener(int viewId, View.OnClickListener clickListener) {
View view = getView(viewId);
view.setOnClickListener(clickListener);
return this;
}
/**
* 指定id控件设置是否可见
*
* @param viewId 控件 id
* @param visibility 可见或者隐藏
* @return
*/
public ViewHolder setVisibility(int viewId, int visibility) {
View view = getView(viewId);
view.setVisibility(visibility);
return this;
}
/**
* 指定id控件设置tag标签
*
* @param viewId 控件id
* @param obj 标签
* @return
*/
public ViewHolder setTag(int viewId, Object obj) {
getView(viewId).setTag(obj);
return this;
}
}
}
14.这样基本上这个控件就做好了,然后去看看怎么用:activity_main.xml 首先弄一个主的activity
对应的布局文件是:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns: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"
android:orientation="vertical"
tools:context=".HomeActivity">
<!--多选控件-->
<com.maddox.mmrrr1.MPopListView
android:id="@+id/mpop_list_view"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<!-- 按钮 获取已选择数据-->
<Button
android:id="@+id/btn_getSelect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="15dp"
android:text="获取已选择的数据" />
<TextView
android:id="@+id/tv_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" />
</LinearLayout>
15.可以看到上面定义了我们刚自己定义的控件.然后
package com.maddox.mmrrr1;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
/**
* 多选列表示例页面
*/
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
//测试多选
MPopListView popListView = findViewById(R.id.mpop_list_view);
Button button = findViewById(R.id.btn_getSelect);
TextView textView = findViewById(R.id.tv_show);
//可选配置
//popListView.setItemTextColor(Color.BLACK);//设置条目的文本颜色
//popListView.setItemTextIcon(R.mipmap.ic_launcher);//设置条目的右侧小图标
//popListView.setItemBackgroundDrawable(getDrawable(R.drawable.selector_btn_normal));//设置条目的背景色 边线 点击效果
//popListView.setArrowImage(R.mipmap.ic_launcher);//设置调出菜单选项的图标
//虚拟假数据
//设置初始化数据,也就是选择数据列表
popListView.setInitList(getTestData());
//获取选择的数据
button.setOnClickListener(v -> {
List<DataModel> selectedList = popListView.getSelectedList();
textView.setText(selectedList.toString());
});
}
//假数据
private List<DataModel> getTestData() {
//初始化显示的假数据
List<DataModel> list = new ArrayList<>();
list.add(new DemoModel(0, "北京市", false));
list.add(new DemoModel(1, "承德市 ", false));
list.add(new DemoModel(2, "澳门半岛 ", false));
list.add(new DemoModel(3, "台中市", false));
list.add(new DemoModel(4, "阳江市", false));
list.add(new DemoModel(5, "张家界", false));
list.add(new DemoModel(6, "邵阳市", false));
list.add(new DemoModel(7, "保山市", false));
list.add(new DemoModel(8, "遵义市 ", false));
list.add(new DemoModel(9, "茂名市", false));
list.add(new DemoModel(10, "宜昌市", false));
list.add(new DemoModel(11, "潍坊市", false));
list.add(new DemoModel(12, "日照市", false));
list.add(new DemoModel(13, "河池市", false));
list.add(new DemoModel(14, "桂林市", false));
list.add(new DemoModel(15, "海口市", false));
return list;
}
}
可以看到先按照上面这样使用,设置初始化的数据,以及获取选中的数据.
16.然后再去补充一下,其他用法:
这里获取选中的,选项的key,这些key就是数据库中的数据库字典的值,用,隔开
MPopListView layout_mdd_docreate_mpl_zhiyexiguan = findViewById(R.id.layout_mdd_docreate_mpl_zhiyexiguan);
List<DataModel> zhiyexiguanSelectedList = layout_mdd_docreate_mpl_zhiyexiguan.getSelectedList();
String zhiyexiguanKey = "";
for(DataModel dataModel:zhiyexiguanSelectedList){
DemoModel tempDemodel = (DemoModel)dataModel;
zhiyexiguanKey = zhiyexiguanKey + String.valueOf(tempDemodel.getId()) +",";
}
if(StringUtils.isNotEmpty(zhiyexiguanKey) && -1!=zhiyexiguanKey.lastIndexOf(",")){
zhiyexiguanKey = zhiyexiguanKey.substring(0, zhiyexiguanKey.lastIndexOf(","));
}
baseInfo.put("temp2",zhiyexiguanKey);
可以看到,上面把结果取出来,然后拼接成 1,2,3..这样的,用户多选的字典值的字符串了,获取以后可以传递到数据库保存起来.
17.然后初始化这个多选框,也给出个例子,上面已经有了,再写一个吧.
String workHabitsResult = YdHttpPostUtils.getDict("workHabits");
workHabitsPair = YdCommonUtils.getDictPairs(workHabitsResult,workHabitsPair);
MPopListView layout_mdd_docreate_mpl_zhiyexiguan = (MPopListView)findViewById(R.id.layout_mdd_docreate_mpl_zhiyexiguan);
List<DataModel> zhiyexiguanMpopListView = new ArrayList<DataModel>();
for(DictPair dictPair:workHabitsPair){
DataModel dataModel = new DemoModel(Integer.valueOf(dictPair.getKey()),dictPair.getValue(),false);
zhiyexiguanMpopListView.add(dataModel);
}
layout_mdd_docreate_mpl_zhiyexiguan.setInitList(zhiyexiguanMpopListView);
18.然后主要是这里,这里根据数据库获取的值,然后动态填充,多选框的多选情况
List<DataModel> zhiyexiguanDatas = new ArrayList<DataModel>();
String zhiyexiguanKey = dataObj.getString("temp2");
if(StringUtils.isNotEmpty(zhiyexiguanKey) && !"null".equals(zhiyexiguanKey)){
String[] zhiyexiguanArray = zhiyexiguanKey.split(",");
List<String> zhiyexiguanList = Arrays.asList(zhiyexiguanArray);
for (DictPair dictPair:workHabitsPair){
if(zhiyexiguanList.contains(dictPair.getKey())){
DemoModel demoModel= new DemoModel(Integer.valueOf(dictPair.getKey()),dictPair.getValue(),true);
zhiyexiguanDatas.add(demoModel);
}
}
}
MPopListView layout_mdd_docreate_mpl_zhiyexiguan = findViewById(R.id.layout_mdd_docreate_mpl_zhiyexiguan);
layout_mdd_docreate_mpl_zhiyexiguan.setSelectDataList(zhiyexiguanDatas);
19.然后看一下效果:
到这里就完了,这个有个案例程序:可以下载去查看,如果看文章没有看明白.
SmartMultiSelecte.zip-Linux文档类资源-CSDN下载
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。