一. 前言 完善之前的自定义View-XLBottomView
Github地址:XLNewBottomView
二. 问题概述 我们先看,与之前不同的地方,之前的子Item,我是想使用我之前写的自定义View:自定义View-XLItem/ 。
但是由于我使用之后没有显示出来,就换成了代码里面的 MyItem类 作为代替。
在这篇文章中,我通过使用 XLNewItem类 来解决过去的问题。
在 XLItem类中,我是使用 xml文件 加载布局的,肯定在那一部分出现了问题。由于父视图肯定会在 onLayout方法中 让子视图调用其 layout 方法。那么我就在 子视图的 onLayout方法 中使用代码添加控件。
三. XLNewItem的内容 1. 自定义属性的文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <declare-styleable name ="XLNewItem" > <attr name ="icon_id" format ="reference" /> <attr name ="title" format ="string" /> <attr name ="normal_color_item" format ="color" /> <attr name ="select_color_item" format ="color" /> <attr name ="text_size" format ="integer" /> <attr name ="icon_size" format ="integer" /> <attr name ="spacing" format ="integer" /> </declare-styleable >
2. 自定义的XLNewItem 由于文本居中不好设置,所以我通过自己 drawText 来绘制文本。
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 public class XLNewItem extends RelativeLayout { public static final String TAG = XLNewItem.class.getSimpleName(); private int icon_id = R.drawable.ic_launcher_background; private String title = "测试" ; private Paint paint; private int text_size = 14 ; private int icon_size = 20 ; private int spacing = 5 ; private int normal_color = Color.BLACK; private int select_color = Color.MAGENTA; private int item_index = 0 ; private ImageView icon_view; private TextView title_view; public static final int STATUS_NORMAL = 0 ; public static final int STATUS_SELECT = 1 ; private TextResource textResource; public XLNewItem (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; init(); } public XLNewItem (Context context, @Nullable AttributeSet attrs) { super (context, attrs); if (attrs != null ){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.XLNewItem); icon_id = typedArray.getResourceId(R.styleable.XLNewItem_icon_id,icon_id); title = typedArray.getString(R.styleable.XLNewItem_title); normal_color = typedArray.getColor(R.styleable.XLNewItem_normal_color_item,normal_color); select_color = typedArray.getColor(R.styleable.XLNewItem_select_color_item,select_color); text_size = typedArray.getInteger(R.styleable.XLNewItem_text_size,text_size); icon_size = typedArray.getInteger(R.styleable.XLNewItem_icon_size, icon_size); spacing = typedArray.getInteger(R.styleable.XLNewItem_spacing,spacing); typedArray.recycle(); } init(); } private void init () { paint = new Paint(); paint.setTextSize(PxUtil.spToPx(text_size,getContext())); paint.setColor(normal_color); textResource = new TextResource(); } public void changeStatus (int status) { if (status == STATUS_NORMAL){ icon_view.setColorFilter(normal_color); paint.setColor(normal_color); }else { icon_view.setColorFilter(select_color); paint.setColor(select_color); } invalidate(); } @SuppressLint("DrawAllocation") @Override protected void onLayout (boolean changed, int l, int t, int r, int b) { super .onLayout(changed, l, t, r, b); int textWidth = (int ) paint.measureText(title); int textHeight = (int ) (paint.getFontMetrics().bottom-paint.getFontMetrics().top); int icon_size = PxUtil.dpToPx(this .icon_size,getContext()); int padding_icon = (getWidth() - icon_size) / 2 ; int padding_top = PxUtil.dpToPx(this .spacing,getContext()); int spacing = PxUtil.dpToPx(this .spacing,getContext()); int padding_text = (getWidth() - textWidth) / 2 ; if (changed){ Log.d(TAG,"XLNewItem:+" +item_index+"开始layout了" ); icon_view = new ImageView(getContext()); title_view = new TextView(getContext()); icon_view.setImageResource(icon_id); int icon_left = padding_icon; int icon_top = padding_top; int icon_right = icon_left + icon_size; int icon_bottom = icon_top + icon_size; int text_left = padding_text; int text_top = icon_bottom + spacing; int text_right = text_left + textWidth; int text_bottom = text_top + textHeight; textResource.x = text_left; int distance = (int ) (textHeight / 2 - paint.getFontMetrics().bottom); textResource.y = text_top + (getHeight()-text_top) / 2 + distance; textResource.text = title; icon_view.layout(icon_left,icon_top,icon_right,icon_bottom); title_view.layout(text_left,text_top,text_right,text_bottom); addView(icon_view); addView(title_view); changeStatus(STATUS_NORMAL); } } private class TextResource { int x; int y; String text; } @Override protected void dispatchDraw (Canvas canvas) { super .dispatchDraw(canvas); canvas.drawText( textResource.text, textResource.x, textResource.y, paint ); } public int getItem_index () { return item_index; } public int getIcon_id () { return icon_id; } public String getTitle () { return title; } }
四. XLNewBottomView 1. 自定义的属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <declare-styleable name ="XLNewBottomView" > <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 >
2. XLNewBottomView 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 public class XLNewBottomView extends RelativeLayout { public static final String TAG = XLNewBottomView.class.getSimpleName(); private int normal_color = Color.BLACK; private int select_color = Color.MAGENTA; private boolean hasLeftOrRightSize = true ; private int item_size = 50 ; private boolean isSelectClick = false ; private XLNewItem lastItem; private XLBottomViewItemListener listener; private List<XLNewItem> items; public XLNewBottomView (Context context, int normal_color, int select_color, boolean hasLeftOrRightSize, int item_size) { super (context); this .normal_color = normal_color; this .select_color = select_color; this .hasLeftOrRightSize = hasLeftOrRightSize; this .item_size = item_size; init(); } public XLNewBottomView (Context context, AttributeSet attrs) { super (context, attrs); if (attrs != null ){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.XLNewBottomView); normal_color = typedArray.getColor(R.styleable.XLNewBottomView_normal_color,normal_color); select_color = typedArray.getColor(R.styleable.XLNewBottomView_select_color,select_color); hasLeftOrRightSize = typedArray.getBoolean(R.styleable.XLNewBottomView_hasLeftOrRightSize,hasLeftOrRightSize); item_size = typedArray.getInteger(R.styleable.XLNewBottomView_item_size,item_size); isSelectClick = typedArray.getBoolean(R.styleable.XLNewBottomView_isSelectClick,isSelectClick); typedArray.recycle(); } init(); } private void init () {} @Override protected void onLayout (boolean changed, int l, int t, int r, int b) { Log.d(TAG,"XLNewBottomView开始layout了" ); 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++) { XLNewItem item = items.get(i); @SuppressLint("DrawAllocation") XLNewItem item_view = new XLNewItem( getContext(), item.getIcon_id(), item.getTitle(), 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(XLNewItem.STATUS_SELECT); lastItem = item_view; }else { item_view.changeStatus(XLNewItem.STATUS_NORMAL); } item_view.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { XLNewItem selectItem = (XLNewItem) v; if (!lastItem.equals(selectItem)) { lastItem.changeStatus(XLNewItem.STATUS_NORMAL); selectItem.changeStatus(XLNewItem.STATUS_SELECT); lastItem = selectItem; if (listener != null ){ listener.itemStatusDidChange(selectItem.getItem_index()); } }else { if (isSelectClick) { if (listener != null ){ listener.itemStatusDidChange(selectItem.getItem_index()); } } } } }); } } } } public interface XLBottomViewItemListener { void itemStatusDidChange (int index) ; } public void setItems (List<XLNewItem> items) { this .items = items; } public void setXLBottomViewItemListener (XLBottomViewItemListener listener) { this .listener = listener; } public void setSelectClick (boolean select) { isSelectClick = select; } }
五. 具体的使用 首先需要添加依赖,添加依赖之后,在布局文件中这样调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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.xlnewbottomview.XLNewBottomView 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" app:isSelectClick="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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); XLNewBottomView bottomView = findViewById(R.id.bottom_view); List<XLNewItem> items = new ArrayList<>(); XLNewItem item1 = new XLNewItem( this , R.drawable.contact, "用户1" , 0 , Color.BLACK, Color.MAGENTA ); XLNewItem item2 = new XLNewItem( this , R.drawable.contact, "用户2" , 0 , Color.BLACK, Color.MAGENTA ); XLNewItem item3 = new XLNewItem( this , R.drawable.contact, "用户3" , 0 , Color.BLACK, Color.MAGENTA ); XLNewItem item4 = new XLNewItem( this , R.drawable.contact, "用户4" , 0 , Color.BLACK, Color.MAGENTA ); items.add(item1); items.add(item2); items.add(item3); items.add(item4); bottomView.setItems(items); bottomView.setXLBottomViewItemListener(new XLNewBottomView.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(); } }); } }