Android最牛逼的多條件篩選選單
說明
本來很懶,但是還是會忍不住的寫下這有用既沒有用的所謂技術部落格,希望會給你帶來有所啟發,因為這樣的功能,寫的人很多,也是為了自己能夠理解的夠透徹,也是為了大家也能更好的理解吧,其實自定義控制元件,也就是那麼回事,沒有什麼可難的,好吧,可能是這個太簡單了。
這是58,趕集都用到的控制元件,這樣的控制元件,自定義起來其實也並不難,自己專案當中用到了這個,於是就研究了一番,可能在你的專案當中也有可能會遇到這樣的需求,正好,也可以來研究下,說真的,今天你見到的這個效果,比58,和趕集做的效果 要好多了,他們做的真的很low。
效果展示
先來看下他長什麼樣子吧
對,就是這個樣子,今天我們就來看看到底是怎麼做出來的。
思路
整體的所有佈局都是用程式碼創建出來的,不是寫死在佈局檔案裡的,這樣會更靈活
- 建立選單欄,就是地址呀,年齡,性別的佈局,水平的LinearLayout
- 向選單欄裡添加布局,就是一個簡單的TextView,和分割線,然後將該佈局新增至父控制元件中,就是最外層佈局
- 建立下劃線,再新增至父控制元件中
- 建立內容顯示區,注意,內容顯示區包括上圖中的顯示的內容(這裡是內容區域),還有點選下拉選單出來的佈局,和半透明的背景,都是在內容區的,他的佈局是FrameLayout,注意FrameLayout的特點,有不熟悉他的特點的可以先查一下他的特點,這樣就會更好的理解這個控制元件的繪製了。
- 內容顯示區為FrameLayout,他裡面包括3部分,最裡層是真正的的內容顯示區,就是上圖中看到的文字(這裡是內容區域),中間層是半透明區域,就是大家看到的變暗的背景,最外層是點選下拉選單之後彈出來的內容
程式碼實現
下面將會帶你用程式碼我做這個控制元件的思路
public class DropDownMenu extends LinearLayout {
//頂部選單佈局
private LinearLayout tabMenuView;
//底部容器,包含popupMenuViews,maskView
private FrameLayout containerView;
//彈出選單父佈局
private FrameLayout popupMenuViews;
//遮罩半透明View,點選可關閉DropDownMenu
private View maskView;
//tabMenuView裡面選中的tab位置,-1表示未選中
private int current_tab_position = -1;
//分割線顏色
private int dividerColor = 0xffcccccc;
//tab選中顏色
private int textSelectedColor = 0xff890c85;
//tab未選中顏色
private int textUnselectedColor = 0xff111111;
//遮罩顏色
private int maskColor = 0x88888888;
//tab字型大小
private int menuTextSize = 14;
//tab選中圖示
private int menuSelectedIcon;
//tab未選中圖示
private int menuUnselectedIcon;
public DropDownMenu(Context context) {
super(context, null);
}
public DropDownMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(VERTICAL);
//為DropDownMenu新增自定義屬性
int menuBackgroundColor = 0xffffffff;
int underlineColor = 0xffcccccc;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu);
underlineColor = a.getColor(R.styleable.DropDownMenu_underlineColor, underlineColor);
dividerColor = a.getColor(R.styleable.DropDownMenu_dividerColor, dividerColor);
textSelectedColor = a.getColor(R.styleable.DropDownMenu_textSelectedColor, textSelectedColor);
textUnselectedColor = a.getColor(R.styleable.DropDownMenu_textUnselectedColor, textUnselectedColor);
menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_menuBackgroundColor, menuBackgroundColor);
maskColor = a.getColor(R.styleable.DropDownMenu_maskColor, maskColor);
menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_menuTextSize, menuTextSize);
menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_menuSelectedIcon, menuSelectedIcon);
menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_menuUnselectedIcon, menuUnselectedIcon);
a.recycle();
//初始化tabMenuView並新增到tabMenuView
tabMenuView = new LinearLayout(context);
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tabMenuView.setOrientation(HORIZONTAL);
tabMenuView.setBackgroundColor(menuBackgroundColor);
tabMenuView.setLayoutParams(params);
addView(tabMenuView, 0);
//為tabMenuView新增下劃線
View underLine = new View(getContext());
underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f)));
underLine.setBackgroundColor(underlineColor);
addView(underLine, 1);
//初始化containerView並將其新增到DropDownMenu
containerView = new FrameLayout(context);
containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
addView(containerView, 2);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
注意下面的成員變數
private LinearLayout tabMenuView;////頂部選單佈局
private FrameLayout containerView;//底部容器,包含popupMenuViews,maskView(暗色背景)
private FrameLayout popupMenuViews;//彈出選單父佈局
private View maskView;//遮罩半透明View,點選可關閉DropDownMenu
public class DropDownMenu extends LinearLayout {}
也就說整體的佈局是繼承自LinearLayout的
setOrientation(VERTICAL);//在第三個構造方法裡指定了整體佈局的方向
完成了以上步驟,其實大體上的佈局差不多都搭好了,下面就是填充子佈局和資料的問題了
/**
* 初始化DropDownMenu
*
* @param tabTexts
* @param popupViews
* @param contentView
*/
public void setDropDownMenu(@NonNull List<String> tabTexts, @NonNull List<View> popupViews, @NonNull View contentView) {
if (tabTexts.size() != popupViews.size()) {
throw new IllegalArgumentException("params not match, tabTexts.size() should be equal popupViews.size()");
}
for (int i = 0; i < tabTexts.size(); i++) {
addTab(tabTexts, i);
}
containerView.addView(contentView, 0);
maskView = new View(getContext());
maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
maskView.setBackgroundColor(maskColor);
maskView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
closeMenu();
}
});
containerView.addView(maskView, 1);
maskView.setVisibility(GONE);
popupMenuViews = new FrameLayout(getContext());
popupMenuViews.setVisibility(GONE);
containerView.addView(popupMenuViews, 2);
for (int i = 0; i < popupViews.size(); i++) {
popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
popupMenuViews.addView(popupViews.get(i), i);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
這一步是對外暴露的方法,專門給選單欄,填充資料,還有為內容區填充佈局的,佈局可以填充任何佈局,很靈活
addTab(tabTexts, i);這個方法,下面會給出程式碼,用來給選單欄添加布局和選單欄的分割線的
containerView.addView(contentView, 0);//將傳入的內容佈局新增到內容區(預設是顯示的)
containerView.addView(maskView, 1);//新增暗色背景(預設是GONG的)
containerView.addView(popupMenuViews, 2);//將點選選單欄後顯示的佈局,注意,這個佈局裡也有子佈局,那就是listview,所以現在是講父佈局新增到內容區的(預設是GONG的)
popupMenuViews.addView(popupViews.get(i), i);//這一步才是為點選選單欄後顯示的佈局填充子佈局的,也就是listview
private void addTab(@NonNull List<String> tabTexts, int i) {
final TextView tab = new TextView(getContext());
tab.setSingleLine();
tab.setEllipsize(TextUtils.TruncateAt.END);
tab.setGravity(Gravity.CENTER);
tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize);
tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
tab.setTextColor(textUnselectedColor);
tab.setCompoundDrawablesWithIntrinsicBounds(null, null, null, getResources().getDrawable(menuUnselectedIcon));
tab.setText(tabTexts.get(i));
tab.setPadding(dpTpPx(5), dpTpPx(12), dpTpPx(5), dpTpPx(12));
//新增點選事件
tab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switchMenu(tab);
}
});
tabMenuView.addView(tab);
//新增分割線
if (i < tabTexts.size() - 1) {
View view = new View(getContext());
LayoutParams layoutParams = new LayoutParams(dpTpPx(0.5f), dpTpPx(25));
layoutParams.gravity = Gravity.CENTER_VERTICAL;
view.setLayoutParams(layoutParams);
view.setBackgroundColor(dividerColor);
tabMenuView.addView(view);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
這一步是為選單欄添加布局,和分割線的,還有為選單欄新增點選事件,沒有什麼可說的
/**
* 切換選單
*
* @param view
*/
private void switchMenu(View view) {
for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
if (view == tabMenuView.getChildAt(i)) {
if (current_tab_position == i) {
closeMenu();
} else {
if (current_tab_position == -1) {
popupMenuViews.setVisibility(View.VISIBLE);
popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));
maskView.setVisibility(VISIBLE);
maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));
popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
} else {
popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
}
current_tab_position = i;
((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);
((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
null, getResources().getDrawable(menuSelectedIcon));
}
} else {
//設定其他未點選tab的狀態
((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);
((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
null, getResources().getDrawable(menuUnselectedIcon));
popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
這一步是切換選單時要做的,只是改變其他狀態而已
用法
做到這,也就意味著,自定義控制元件寫完了,下面就是如何用他了
佈局
<example.fussen.dropdownmenu.DropDownMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dropDownMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:dividerColor="@color/blue_app"
app:maskColor="@color/mask_color"
app:menuBackgroundColor="@color/base_title_color"
app:menuSelectedIcon="@drawable/ic_img_up"
app:menuTextSize="16sp"
app:menuUnselectedIcon="@drawable/ic_img_down"
app:textSelectedColor="@color/blue_app"
app:textUnselectedColor="@color/drop_down_unselected"
app:underlineColor="@color/blue_app" />
將上面的佈局copy到你的佈局裡就ok啦
自定義的屬性
<declare-styleable name="DropDownMenu">
<!--下劃線顏色-->
<attr name="underlineColor" format="color" />
<!--分割線顏色(選單欄)-->
<attr name="dividerColor" format="color" />
<!--tab選中顏色-->
<attr name="textSelectedColor" format="color" />
<!--tab未選中顏色-->
<attr name="textUnselectedColor" format="color" />
<!--tab 背景顏色-->
<attr name="menuBackgroundColor" format="color" />
<!--遮罩顏色,一般是半透明-->
<attr name="maskColor" format="color" />
<!--字型大小-->
<attr name="menuTextSize" format="dimension" />
<!--tab選中狀態圖示-->
<attr name="menuSelectedIcon" format="reference" />
<!--tab未選中狀態圖示-->
<attr name="menuUnselectedIcon" format="reference" />
</declare-styleable>
結束
- ok,做到這,就大功告成了,具體的程式碼還是以我的Demo為主
- 如果需要原始碼,關注微信公共號:AppCode,回覆關鍵字“篩選選單”,即可拿到原始碼下載的連結
apk下載
如果這篇文章對你有用,歡迎關注我們的微信公共號:AppCode
掃描下面二維碼即可關注