一. 前言 仿照系统的BottomNavigationView而做的效果。
Github地址:XLBottomView
二. 自定义View 1. 自定义用到的属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private int normal_color = Color.BLACK;private int select_color = Color.MAGENTA;private boolean hasLeftOrRightSize = true ;private int item_size = 50 ;private int item_layout;private boolean isSelectClick = false ;private MyItem lastItem;private XLBottomViewItemListener listener;private List<BottomViewItem> items;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static class BottomViewItem { private int icon_id; private String title; public BottomViewItem (int icon_id, String title) { this .icon_id = icon_id; this .title = title; } }
2. 在values文件夹下自定义属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version="1.0" encoding="utf-8"?> <resources > <declare-styleable name ="XLBottomView" > <attr name ="normal_color" format ="color" /> <attr name ="select_color" format ="color" /> <attr name ="hasLeftOrRightSize" format ="boolean" /> <attr name ="item_size" format ="integer" /> <attr name ="item_layout" format ="reference" /> <attr name ="isSelectClick" format ="boolean" /> </declare-styleable > </resources >
3. 创建构造方法 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 public XLBottomView (Context context, int normal_color, int select_color, boolean hasLeftOrRightSize, int item_size, int item_layout) { super (context); this .normal_color = normal_color; this .select_color = select_color; this .hasLeftOrRightSize = hasLeftOrRightSize; this .item_size = item_size; this .item_layout = item_layout; init(); } public XLBottomView (Context context, AttributeSet attrs) { super (context, attrs); if (attrs != null ){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.XLBottomView); normal_color = typedArray.getColor(R.styleable.XLBottomView_normal_color,normal_color); select_color = typedArray.getColor(R.styleable.XLBottomView_select_color,select_color); hasLeftOrRightSize = typedArray.getBoolean(R.styleable.XLBottomView_hasLeftOrRightSize,hasLeftOrRightSize); item_size = typedArray.getInteger(R.styleable.XLBottomView_item_size,item_size); isSelectClick = typedArray.getBoolean(R.styleable.XLBottomView_isSelectClick,isSelectClick); typedArray.recycle(); } init(); } private void init () {}
4. layout的过程中添加视图 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 82 83 84 85 86 87 88 @Override protected void onLayout (boolean changed, int l, int t, int r, int b) { if (changed){ if (items.size() != 0 ) { Log.d(TAG,"数据来了" ); int space_num = hasLeftOrRightSize ? items.size()+1 : items.size()-1 ; int horizon_size = (getWidth() - items.size() * PxUtil.dpToPx(item_size,getContext())) / space_num; int vertical_size = (getHeight()- PxUtil.dpToPx(item_size,getContext())) / 2 ; for (int i = 0 ; i < items.size(); i++) { BottomViewItem item = items.get(i); @SuppressLint("DrawAllocation") MyItem item_view = new MyItem( getContext(), item.icon_id, item.title, i, normal_color, select_color ); int left = hasLeftOrRightSize ? horizon_size + (horizon_size + PxUtil.dpToPx(item_size,getContext())) * i : (horizon_size + PxUtil.dpToPx(item_size,getContext())) * i; if (!hasLeftOrRightSize){ if (i == 0 ) left += PxUtil.dpToPx(20 ,getContext()); if (i == items.size()-1 ) left -= PxUtil.dpToPx(20 ,getContext()); } int top = vertical_size; int right = left + PxUtil.dpToPx(item_size,getContext()); int bottom = top + PxUtil.dpToPx(item_size,getContext()); item_view.layout(left,top,right,bottom); Log.d(TAG,"left:" +left+" top:" +top); addView(item_view); if (i == 0 ) { item_view.changeStatus(MyItem.STATUS_SELECT); lastItem = item_view; }else { item_view.changeStatus(MyItem.STATUS_NORMAL); } item_view.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { MyItem selectItem = (MyItem) v; if (!lastItem.equals(selectItem)) { lastItem.changeStatus(MyItem.STATUS_NORMAL); selectItem.changeStatus(MyItem.STATUS_SELECT); lastItem = selectItem; if (listener != null ){ listener.itemStatusDidChange(selectItem.getItem_index()); } } } }); } } } }
5. 子项类 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 82 83 84 85 public class MyItem extends androidx .appcompat .widget .AppCompatTextView { private int icon_id; private String title; private int item_index; private int normal_color; private int select_color; public static final int STATUS_NORMAL = 0 ; public static final int STATUS_SELECT = 1 ; public MyItem (Context context, int icon_id, String title, int item_index, int normal_color, int select_color) { super (context); this .icon_id = icon_id; this .title = title; this .item_index = item_index; this .normal_color = normal_color; this .select_color = select_color; setBackground(null ); init(STATUS_NORMAL); } private void init (int status) { Drawable drawable = getResources().getDrawable(icon_id).mutate(); drawable.setBounds(0 ,PxUtil.dpToPx(5 ,getContext()),PxUtil.dpToPx(25 ,getContext()),PxUtil.dpToPx(25 ,getContext())+PxUtil.dpToPx(5 ,getContext())); setCompoundDrawables(null ,drawable,null ,null ); setCompoundDrawablePadding(PxUtil.dpToPx(8 ,getContext())); setText(title); setTextSize(PxUtil.spToPx(5 ,getContext())); setGravity(Gravity.CENTER); setTextColor(normal_color); } public void changeStatus (int status) { if (status == STATUS_SELECT){ getCompoundDrawables()[1 ].mutate().setColorFilter(select_color, PorterDuff.Mode.SRC_ATOP); setTextColor(select_color); }else if (status == STATUS_NORMAL){ getCompoundDrawables()[1 ].mutate().setColorFilter(normal_color, PorterDuff.Mode.SRC_ATOP); setTextColor(normal_color); } } public int getItem_index () { return item_index; } }
在这里,我们需要了解ColorFilter。
简单的理解可以参考这篇文章:ColorFilter的使用 以及 Android-使用 SetColorFilter 神奇地改变图片的颜色
但是,如果使用setColorFilter,还是有一个坑需要了解,参考这篇文章:Android-Drawable setColorFilter方法踩坑
三. 具体的使用 首先需要添加依赖,添加依赖之后,在布局文件中这样调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context =".MainActivity" > <swu.xl.bottomview.XLBottomView android:id="@+id/bottom_view" android:layout_width="match_parent" android:layout_height="60dp" android:background="#999999" app:normal_color="#000000" app:select_color="#ff9900" app:hasLeftOrRightSize="false" app:item_size="50" android:layout_alignParentBottom="true" /> </RelativeLayout >
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 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); XLBottomView bottomView = findViewById(R.id.bottom_view); List<XLBottomView.BottomViewItem> items = new ArrayList<>(); XLBottomView.BottomViewItem item1 = new XLBottomView.BottomViewItem( R.drawable.contact, "用户1" ); XLBottomView.BottomViewItem item2 = new XLBottomView.BottomViewItem( R.drawable.contact, "用户2" ); XLBottomView.BottomViewItem item3 = new XLBottomView.BottomViewItem( R.drawable.contact, "用户3" ); XLBottomView.BottomViewItem item4 = new XLBottomView.BottomViewItem( R.drawable.contact, "用户4" ); items.add(item1); items.add(item2); items.add(item3); items.add(item4); bottomView.setItems(items); bottomView.setXLBottomViewItemListener(new XLBottomView.XLBottomViewItemListener() { @Override public void itemStatusDidChange (int index) { Toast toast = Toast.makeText(MainActivity.this , "第" + (index + 1 ) + "个按钮被点击" , Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER,0 ,0 ); toast.show(); } }); } }