Android?自定義?Dialog?實現(xiàn)列表?單選、多選、搜索功能
前言
在Android開發(fā)中,通過對話框讓用戶選擇,篩選信息是很方便也很常見的操作。本文詳細介紹了如何使用自定義 Dialog、RecyclerView 以及自定義搜索框 來實現(xiàn)選中狀態(tài)和用戶交互,文中大本分代碼都有明確注釋,主打一個簡單明了,實際效果如下,可單選,全選,精準查找,選擇狀態(tài)變化,以及信息回調(diào)

一、Builder 模式
說到自定義 Dialog,就不得不提到 Builder模式,
Android系統(tǒng)中的Builder設計模式是一種創(chuàng)建型設計模式,它主要用于構(gòu)建一個復雜對象,并將其構(gòu)建過程與表示分離,Builder設計模式通過將一個復雜對象的構(gòu)建過程拆解成一系列簡單的步驟,使得構(gòu)建過程更加靈活、可讀和易于擴展。它允許用戶在不知道內(nèi)部構(gòu)建細節(jié)的情況下,可以更精細地控制對象的構(gòu)造流程。
在Android開發(fā)中,Builder模式的一個常見應用是AlertDialog.Builder。AlertDialog是一個復雜的對話框?qū)ο?,它包含多個屬性和方法。使用AlertDialog.Builder可以方便地構(gòu)建和顯示對話框,而無需直接操作AlertDialog對象。例如:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon);
builder.setTitle("頭部");
builder.setMessage("內(nèi)容");
builder.setPositiveButton("Button1", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// 處理點擊事件
}
});
builder.create().show(); // 構(gòu)建并顯示對話框綜上所述,Builder設計模式在Android開發(fā)中具有重要的應用價值。它可以幫助開發(fā)者構(gòu)建復雜對象,提高代碼的可讀性和可維護性,同時支持靈活的構(gòu)建過程和對象變種。
二、使用步驟
1. 自定義 SerachSelectDialog
public class SerachSelectDialog extends Dialog {
private static SearchSelectAdapter sa;
private static String result;
private static List<String> resultList = new ArrayList<>();
private static List<String> selectedItems;
private static int searchPosition;
public SerachSelectDialog(Context context, int themeResId) {
super(context, themeResId);
}
/**
* 設置 Dialog的大小
*
* @param x 寬比例
* @param y 高比例
*/
public void setDialogWindowAttr(double x, double y, Activity activity) {
if (x < 0 || x > 1 || y < 0 || y > 1) {
return;
}
Window window = this.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
WindowManager manager = activity.getWindowManager();
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
int height = outMetrics.heightPixels;
lp.gravity = Gravity.BOTTOM;
lp.width = (int) (width * x);
lp.height = (int) (height * y);
this.getWindow().setAttributes(lp);
}
public static class Builder {
private String title;
private View contentView;
private String positiveButtonText;
private String negativeButtonText;
private List<ItemModel> listData;
private View.OnClickListener positiveButtonClickListener;
private View.OnClickListener negativeButtonClickListener;
private View.OnClickListener singleButtonClickListener;
private View layout;
private Context context;
private SerachSelectDialog dialog;
private OnSelectedListiner selectedListiner;
SearchView searchView;
LinearLayout closeBtn;
LinearLayout okBtn;
TextView titleView;
private boolean state = false;
private RecyclerView itemLv;
private final TextView qxTv;
//初始化
public Builder(Context context) {
//這里傳入自定義的style,直接影響此Dialog的顯示效果。style具體實現(xiàn)見style.xml
this.context = context;
dialog = new SerachSelectDialog(context, R.style.selectDialog);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = inflater.inflate(R.layout.dialog_select_search, null);
qxTv = layout.findViewById(R.id.qx_tv);
itemLv = layout.findViewById(R.id.item_lv);
searchView = layout.findViewById(R.id.searchView);
closeBtn = layout.findViewById(R.id.diss_layout);
okBtn = layout.findViewById(R.id.ok_layout);
titleView = layout.findViewById(R.id.title_tv);
dialog.addContentView(layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
public Builder setTitle(String title) {
this.title = title;
return this;
}
public void setListData(List<ItemModel> listData) {
this.listData = listData;
}
/**
* 單按鈕對話框和雙按鈕對話框的公共部分在這里設置
*/
private SerachSelectDialog create() {
GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 3);
sa = new SearchSelectAdapter(listData);
itemLv.setLayoutManager(gridLayoutManager);
itemLv.setAdapter(sa);
//搜索事件
searchView.setSearchViewListener(new SearchView.onSearchViewListener() {
@Override
public boolean onQueryTextChange(String text) {
updateLayout(searchItem(text));
return false;
}
});
//全選
qxTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (sa.getSelectedItemPositions().size() == sa.getItemCount()) {
sa.clearSelection();
} else {
sa.selectAll();
resultList = sa.getSelectedItems();
}
}
});
//取消按鈕
closeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
resultList.clear();
}
});
//確認按鈕
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String json = new Gson().toJson(resultList);
selectedListiner.onSelected(json);
dialog.dismiss();
resultList.clear();
}
});
dialog.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
});
//item點擊事件
sa.setOnItemClickListener(new SearchSelectAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
boolean selected = listData.get(position).isSelected();
result = listData.get(position).getItemName();
if (selected == true) {
resultList.add(result);
} else {
resultList.remove(result);
}
Log.i("U--", resultList.toString() + selected + "");
}
});
dialog.setContentView(layout);
//用戶可以點擊手機Back鍵取消對話框顯示
dialog.setCancelable(true);
//用戶不能通過點擊對話框之外的地方取消對話框顯示
dialog.setCanceledOnTouchOutside(false);
return dialog;
}
//在數(shù)據(jù)源中查找匹配的數(shù)據(jù)
public List<ItemModel> searchItem(String name) {
ArrayList<ItemModel> mSearchList = new ArrayList<ItemModel>();
for (int i = 0; i < listData.size(); i++) {
int index = listData.get(i).getItemName().indexOf(name);
// 存在匹配的數(shù)據(jù)
if (index != -1) {
mSearchList.add(listData.get(i));
Log.i("U--", i + "搜索位置");
searchPosition = i;
}
}
return mSearchList;
}
//提供匹配后的的數(shù)據(jù)進行數(shù)據(jù)回調(diào)
public void updateLayout(List<ItemModel> newList) {
final SearchSelectAdapter sa = new SearchSelectAdapter(newList);
GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 3);
itemLv.setLayoutManager(gridLayoutManager);
itemLv.setAdapter(sa);
//item點擊事件
sa.setOnItemClickListener(new SearchSelectAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
result = newList.get(position).getItemName();
boolean selected = listData.get(searchPosition).isSelected();
if (selected == true) {
resultList.add(result);
} else {
resultList.remove(result);
}
Log.i("U--", resultList.toString() + selected + "");
}
});
}
//自定義接口進行數(shù)據(jù)點擊回傳
public static abstract class OnSelectedListiner {
public abstract void onSelected(String String);
}
public void setSelectedListiner(SerachSelectDialog.Builder.OnSelectedListiner selectedListiner) {
this.selectedListiner = selectedListiner;
}
//彈框展示
public SerachSelectDialog show() {
create();
dialog.show();
return dialog;
}
}
}2.自定義搜索框 SearchView
UI 主要包括輸入框,刪除鍵 ,主要通過監(jiān)聽EditText 的文本以及輸入框的變化,設置搜索回調(diào)接口來實現(xiàn)
public class SearchView extends LinearLayout implements View.OnClickListener {
/**
* 輸入框
*/
private EditText etInput;
/**
* 刪除鍵
*/
private ImageView ivDelete;
/**
* 上下文對象
*/
private Context mContext;
/**
* 搜索回調(diào)接口
*/
private onSearchViewListener mListener;
/**
* 設置搜索回調(diào)接口
*
* @param listener 監(jiān)聽者
*/
public void setSearchViewListener(onSearchViewListener listener) {
mListener = listener;
}
public SearchView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
LayoutInflater.from(context).inflate(R.layout.view_search_layout, this);
initViews();
}
private void initViews() {
etInput = (EditText) findViewById(R.id.et_search_text);
ivDelete = (ImageView) findViewById(R.id.imb_search_clear);
ivDelete.setOnClickListener(this);
etInput.addTextChangedListener(new EditChangedListener());
etInput.setOnClickListener(this);
}
private class EditChangedListener implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
if (!"".equals(charSequence.toString())) {
ivDelete.setVisibility(VISIBLE);
//更新autoComplete數(shù)據(jù)
if (mListener != null) {
mListener.onQueryTextChange(charSequence + "");
}
} else {
ivDelete.setVisibility(GONE);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.imb_search_clear:
etInput.setText("");
if (mListener != null) {
mListener.onQueryTextChange("");
}
ivDelete.setVisibility(GONE);
break;
}
}
/**
* search view回調(diào)方法
*/
public interface onSearchViewListener {
boolean onQueryTextChange(String text);
}
} 3.SearchSelectAdapter
主要實現(xiàn)條目的點擊事件以及數(shù)據(jù)回調(diào)
public class SearchSelectAdapter extends RecyclerView.Adapter<SearchSelectAdapter.ViewHolder> {
private List<ItemModel> itemList;
private List<Integer> selectedItemPositions;
//聲明接口
private OnItemClickListener onItemClickListener;
public SearchSelectAdapter(List<ItemModel> itemList) {
this.itemList = itemList;
selectedItemPositions = new ArrayList<>();
}
@Override
public int getItemCount() {
return itemList.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 創(chuàng)建ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_cell_select_single, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// 綁定數(shù)據(jù)到ViewHolder
ItemModel item = itemList.get(position);
holder.textView.setText(item.getItemName());
//給條目布局設置點擊事件
holder.itemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (selectedItemPositions.contains(position)) {
selectedItemPositions.remove(Integer.valueOf(position));
holder.textView.setTextColor(Color.BLACK);
holder.itemView.setBackgroundResource(R.drawable.item_grey_layout_bg);
item.setSelected(false);
} else {
selectedItemPositions.add(position);
holder.textView.setTextColor(Color.WHITE);
holder.itemView.setBackgroundResource(R.drawable.item_blue_layout_bg);
item.setSelected(true);
}
if (onItemClickListener != null) {
onItemClickListener.onItemClick(position);
}
}
});
if (selectedItemPositions.contains(position)) {
holder.textView.setTextColor(Color.WHITE);
holder.itemView.setBackgroundResource(R.drawable.item_blue_layout_bg);
} else {
holder.textView.setTextColor(Color.BLACK);
holder.itemView.setBackgroundResource(R.drawable.item_grey_layout_bg);
}
}
/**
* 接口回調(diào)
*/
public interface OnItemClickListener {
void onItemClick(int position);
}
public void selectAll() {
selectedItemPositions.clear();
for (int i = 0; i < itemList.size(); i++) {
selectedItemPositions.add(i);
}
notifyDataSetChanged();
}
public void clearSelection() {
selectedItemPositions.clear();
notifyDataSetChanged();
}
public List<Integer> getSelectedItemPositions() {
return selectedItemPositions;
}
public List<String> getSelectedItems() {
List<String> selectedItems = new ArrayList<>();
for (int position : selectedItemPositions) {
selectedItems.add(itemList.get(position).getItemName());
}
return selectedItems;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
private final LinearLayout itemLayout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_select_info);
itemLayout = itemView.findViewById(R.id.item_layout);
}
}
}4.xml 布局
dialog_select_search.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:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/item_white_layout"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="崗位選擇"
android:textColor="@color/black" />
</RelativeLayout>
<com.example.dialoglistview.SearchView
android:id="@+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/qx_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="@dimen/dp_10"
android:text="全選"
android:textSize="16sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/item_lv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/grey" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/transparent"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/diss_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消"
android:textColor="@color/sea_blue" />
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/grey" />
<LinearLayout
android:id="@+id/ok_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="確定"
android:textColor="@color/sea_blue" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>view_search_layout.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="50dp"
android:background="#ffffff"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="@drawable/item_search_layout"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageButton
android:id="@+id/imb_search_search"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="15dp"
android:background="#F0F0F0"
android:scaleType="centerInside"
android:src="@mipmap/im_search_back" />
<EditText
android:id="@+id/et_search_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="15dp"
android:layout_weight="1"
android:background="@null"
android:hint="請輸入搜索內(nèi)容"
android:lines="1"
android:textSize="14sp" />
<ImageButton
android:id="@+id/imb_search_clear"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginRight="20dp"
android:background="#F0F0F0"
android:padding="12.5dp"
android:scaleType="centerInside"
android:src="@mipmap/delet_zhaopian_1x"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>5.數(shù)據(jù)支持
// 創(chuàng)建數(shù)據(jù)列表
itemList = new ArrayList<>();
itemList.add(new ItemModel("醫(yī)生", false));
itemList.add(new ItemModel("警察", false));
itemList.add(new ItemModel("護士", false));
itemList.add(new ItemModel("農(nóng)民", false));
itemList.add(new ItemModel("工人", false));
itemList.add(new ItemModel("司機", false));public class ItemModel {
private String itemName;
private boolean isSelected;
public ItemModel(String itemName, boolean isSelected) {
this.itemName = itemName;
this.isSelected = isSelected;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
}6.實際應用
private void openSearchSelectDialog() {
SerachSelectDialog.Builder alert = new SerachSelectDialog.Builder(this);
alert.setListData(itemList);
alert.setTitle("崗位選擇");
alert.setSelectedListiner(new SerachSelectDialog.Builder.OnSelectedListiner() {
@Override
public void onSelected(String info) {
okTv.setText(info);
}
});
SerachSelectDialog mDialog = alert.show();
//設置Dialog 尺寸
mDialog.setDialogWindowAttr(0.9, 0.9, this);
}三、總結(jié)
后續(xù) Demo 會上傳
到此這篇關(guān)于Android 自定義 Dialog 實現(xiàn)列表 單選,多選,搜索功能的文章就介紹到這了,更多相關(guān)Android 自定義 Dialog 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android自定義Dialog的2種常見方法
- Android自定義Dialog框樣式
- Android自定義Dialog原理實例解析
- Android 自定義加載動畫Dialog彈窗效果的示例代碼
- Android自定義底部彈出框ButtomDialog
- android自定義Dialog彈框和背景陰影顯示效果
- Android自定義Dialog實現(xiàn)通用圓角對話框
- Android自定義dialog 自下往上彈出的實例代碼
- Android 自定義Dialog去除title導航欄的解決方法
- Android自定義Dialog實現(xiàn)加載對話框效果
- Android編程自定義AlertDialog樣式的方法詳解
- 解決Android中自定義DialogFragment解決寬度和高度問題
相關(guān)文章
Android中Fragment與Activity的生命周期對比
這篇文章主要介紹了Android中Fragment與Activity的生命周期對比,Fragment是在Activity的基礎之上進行設計的,比Activity多出幾個控制生命周期的回調(diào)函數(shù),需要的朋友可以參考下2016-02-02
基于Android6.0實現(xiàn)彈出Window提示框
這篇文章主要為大家詳細介紹了基于Android6.0實現(xiàn)彈出Window提示框,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
Android利用ViewDragHelper輕松實現(xiàn)拼圖游戲的示例
本篇文章主要介紹了Android利用ViewDragHelper輕松實現(xiàn)拼圖游戲的示例,非常具有實用價值,需要的朋友可以參考下2017-11-11
Android studio listview實現(xiàn)列表數(shù)據(jù)顯示 數(shù)據(jù)循環(huán)顯示效果
這篇文章主要介紹了Android studio listview實現(xiàn)列表數(shù)據(jù)顯示 數(shù)據(jù)循環(huán)顯示功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
Android view更改背景資源與padding消失的問題解決辦法
這篇文章主要介紹了Android view更改背景資源與padding消失的問題解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04
Android EditText限制輸入字符的方法總結(jié)
這篇文章主要介紹了 Android EditText限制輸入字符的方法總結(jié)的相關(guān)資料,這里提供了五種方法來實現(xiàn)并進行比較,需要的朋友可以參考下2017-07-07
Android使用SharedPreferences存儲數(shù)據(jù)的實現(xiàn)方法
這篇文章主要介紹了Android使用SharedPreferences存儲數(shù)據(jù)的實現(xiàn)方法,可實現(xiàn)針對短信的臨時保存功能,非常簡單實用,需要的朋友可以參考下2016-06-06

