最近总感觉写博客的激情不高,不知道为啥。放上效果图,demo在最下面
图上那个切换按钮的作用呢,就是模拟改变标签的个数动态变化整个控件的高度。
其实这个控件也算很简单的控件了。关键点只有两个
- 如何控制标签自动换行
- 切换数据源时动态改变控件的高度
再简单的控件也需要一点一点的码出来,咱就从最基础的属性设置开始。
复制代码
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
38public FlowTagView textColor(int defaultColor, int selectedColor){ this.textColorDefault = defaultColor; this.textColorSelected = selectedColor; return this; } public FlowTagView textSize(int textSize){ this.textSize = textSize; return this; } public FlowTagView backgroundColor(int defaultColor, int selectedColor){ this.backgroundColorDefault = defaultColor; this.backgroundColorSelected = selectedColor; return this; } public FlowTagView padding(int horizontalPadding, int verticalPadding, int textHorizontalPadding){ this.horizontalPadding = horizontalPadding; this.verticalPadding = verticalPadding; this.textHorizontalPadding = textHorizontalPadding; return this; } public FlowTagView itemHeight(int height){ this.itemHeight = height; return this; } public FlowTagView datas(String[] datas){ this.datas = datas; return this; } public FlowTagView listener(OnTagSelectedListener listener){ this.listener = listener; return this; }
上面设置了字体颜色啊,背景颜色啊,标签Item的高度啊,内补白和外部白的一些值,还有一个监听器。有的朋友就说了,我比较懒,就想快点看到效果,不想设置怎么办?怎么办?给默认值呗。
复制代码
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//常亮默认值,这些参数若不调用方法传递,则直接使用默认值 public static final int ROUND_RADIUS = 30; public static final int TEXT_COLOR_DEFAULT = Color.BLACK; public static final int TEXT_COLOR_SELECTED = Color.WHITE; public static final int TEXT_SIZE = 30; public static final int BACKGROUND_COLOR_DEFAULT = Color.GRAY; public static final int BACKGROUND_COLOR_SELECTED = Color.GREEN; public static final int HORIZONTAL_PADDING = 30; public static final int VERTICAL_PADDING = 30; public static final int TEXT_HORIZONTAL_PADDING = 30; public static final int ITEM_HEIGHT = 60; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private int textColorDefault = TEXT_COLOR_DEFAULT; private int textColorSelected = TEXT_COLOR_SELECTED; private int textSize = TEXT_SIZE; private int backgroundColorDefault = BACKGROUND_COLOR_DEFAULT; private int backgroundColorSelected = BACKGROUND_COLOR_SELECTED; //Tag之间的横向和纵向的间隔 private int horizontalPadding = HORIZONTAL_PADDING; private int verticalPadding = VERTICAL_PADDING; //每个Tag内部的横向间隔 private int textHorizontalPadding = TEXT_HORIZONTAL_PADDING; //每个Tag的高度 private int itemHeight = ITEM_HEIGHT;
好了,基本的属性设置的代码完成了,那么就用软件的高内聚低耦合的思想封装一个标签类吧。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Tag{ //文本属性 public String text; public int textColorDefault; public int textColorSelected; public int backgroundColorDefault; public int backgroundColorSelected; public boolean isSelected; public Paint paint; //文本的绘制起点 public int drawX; public int drawY; //整个Tag占用的坐标范围 public RectF rect = new RectF(); public Tag(String text, int textSize, int textColorDefault, int textColorSelected,
复制代码
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
44int backgroundColorDefault, int backgroundColorSelected, Paint paint, int height, int horizontalPadding, int startX, int startY){ this.text = text; this.textColorDefault = textColorDefault; this.textColorSelected = textColorSelected; this.backgroundColorDefault = backgroundColorDefault; this.backgroundColorSelected = backgroundColorSelected; this.paint = paint; //求出整个Tag的宽度 paint.setTextSize(textSize); int textWidth = (int)paint.measureText(text); int width = textWidth + 2 * horizontalPadding; //计算坐标范围,startX,staryY是指左上角的起点 rect.left = startX; rect.top = startY; rect.right = startX + width; rect.bottom = startY + height; //计算居中绘制时的绘制起点 drawX = startX + horizontalPadding; Paint.FontMetrics metrics = paint.getFontMetrics(); drawY = (int)(startY + height / 2 + (metrics.bottom - metrics.top) / 2 - metrics.bottom); } public void draw(Canvas canvas){ if(isSelected){ //绘制背景 paint.setColor(backgroundColorSelected); paint.setStyle(Paint.Style.FILL); canvas.drawRoundRect(rect, ROUND_RADIUS, ROUND_RADIUS, paint); //绘制文本 paint.setColor(textColorSelected); canvas.drawText(text, drawX, drawY, paint); }else{ //绘制背景 paint.setColor(backgroundColorDefault); paint.setStyle(Paint.Style.STROKE); canvas.drawRoundRect(rect, ROUND_RADIUS, ROUND_RADIUS, paint); //绘制文本 paint.setColor(textColorDefault); canvas.drawText(text, drawX, drawY, paint); } } }
这个封装类就两个方法,一个是构造方法,一个是绘制方法。构造方法就是对属性的一些赋值。然后利用startX和startY计算出每个标签的坐标范围和文本的绘制起点。绘制方法draw(Canvas canvas)就简单得绘制一个文本和一个背景。想定制标签的样式的话,就在这个方法进行重写。
好了,这个封装类其实也不算难。接下来就来到最关键的地方了。startX和startY的取值。
复制代码
1
2
3
4
5
6
7
8
9
10@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int width = MeasureSpec.getSize(widthMeasureSpec); //算出绘制起点 startX = getPaddingLeft(); startY = getPaddingTop(); tags.clear(); for(int i = 0; i < datas.length; i++){ //判断是否越过边界 if(startX + getRealWidth(paint, textSize, datas[i], textHorizontalPadding) + horizontalPadding
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15> width - getPaddingRight()){ //在下一行开始绘制 startX = getPaddingLeft(); startY += itemHeight + verticalPadding; } Tag tag = new Tag(datas[i], textSize, textColorDefault, textColorSelected, backgroundColorDefault, backgroundColorSelected, paint, itemHeight, textHorizontalPadding, startX, startY); tags.add(tag); //动态更新值 startX += getRealWidth(paint, textSize, datas[i], textHorizontalPadding) + horizontalPadding; } //算出整个控件需要的高度 int height = startY + itemHeight + getPaddingBottom(); setMeasuredDimension(width, height); }
这里用到了一个工具方法getRealWidth,这个就是用来计算每一个标签的真实宽度的。
复制代码
1
2
3
4
5
6
7
8/** * 根据参数算出某个Tag所需要占用的宽度值,包括内补白 */ public static int getRealWidth(Paint paint, int textSize, String text, int textHorizontalPadding){ paint.setTextSize(textSize); int textWidth = (int)paint.measureText(text); return textWidth + 2 * textHorizontalPadding; }
代码不多,但是的确是最重要的地方。首先拿到startX和startY的初始值。默认为padding值。然后对文本进行遍历。当当前文本的绘制终点大于该行的最大值,则重置startX,并且将startY累加一次标签的高度值与竖直补白值。然后进行该标签的实例化。然后别忘了对startX进行重新赋值。最后得到整个控件实际得高度,设置该控件的高度。
有的小伙伴就问了,要是我的数据源发生了变化,怎么动态改变高度值以及刷新数据源呢。这也是我刚才提到的第二个重点,这个问题我找了很多办法,最优秀的办法就是利用LayoutParams。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12public void commit(){ if(datas == null){ Log.e("FlowTagView", "maybe not invok the method named datas(String[])"); throw new IllegalStateException("maybe not invok the method named datas(String[])"); } paint.setTextSize(textSize); if(datas.length != tags.size()){ //重新实例化 ViewGroup.LayoutParams params = getLayoutParams(); setLayoutParams(params); } }
在外界设置属性的时候,最后一个链一定要调用commit方法进行提交,这里直接得到当前的LayoutParams,然后再次设置回去。这样做有什么用呢?用处就是为了触发onMeasure方法。哈哈,onMeasure方法会自动进行重计算的。机智如我。
接下来就处理点击事件了,首先定义一个自定义的接口。
复制代码
1
2
3public interface OnTagSelectedListener{ void onTagSelected(FlowTagView view, int position); }
祭出最最最常用的onTouchEvent方法,前提是有几个成员变量。
复制代码
onTouchEvent方法进行事件分发。
1
2
3
4
5
6
7//点击事件的滑动距离阈值 private int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); //ACTION_DOWN时的坐标值 private float mTouchX; private float mTouchY; //ACTION_DOWN时选中的tag的索引 private int mTouchPosition;
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22@Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()){ case MotionEvent.ACTION_DOWN: mTouchX = event.getX(); mTouchY = event.getY(); mTouchPosition = getTagPosition(mTouchX, mTouchY); return true; case MotionEvent.ACTION_UP: float mUpX = event.getX(); float mUpY = event.getY(); //滑动距离小于点击阈值并且点击时的索引值不是非法值,并且up时的索引值和down时的索引值相等时,才触发选中操作 if(Math.abs(mUpX - mTouchX) < mTouchSlop && Math.abs(mUpY - mTouchY) < mTouchSlop && mTouchPosition != -1 && getTagPosition(mUpX, mUpY) == mTouchPosition){ //触发点击选中 setSelect(mTouchPosition); } break; } return super.onTouchEvent(event); }
其实就是一个模拟点击的操作。对于抬起和按下时的坐标不超过一个给定阈值,并且抬起和按下时点击的标签是同一个的话,才触发选中的操作。也就是setSelect方法。
复制代码
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/** * 根本坐标值,返回对应的tag的索引,若不存在则返回-1 */ private int getTagPosition(float x, float y){ for(int i = 0; i < tags.size(); i++){ if(tags.get(i).rect.contains(x, y)){ return i; } } return -1; } public void setSelect(int position){ if(position < 0 || position >= tags.size()){ Log.e("FlowTagView", "the position is illetal"); throw new IllegalArgumentException("the position is illetal"); } for(int i = 0; i < tags.size(); i++){ //关闭其他选择 if(i != position){ tags.get(i).isSelected = false; }else{ tags.get(i).isSelected = true; } } //触发监听器 if(listener != null){ listener.onTagSelected(this, position); } //必须要刷新UI invalidate(); } public int getSelect(){ for(int i = 0; i < tags.size(); i++){ if(tags.get(i).isSelected){ return i; } } return -1; }
好了,这个自定义控件的讲解就结束了,按照我的习惯,此时应该贴出这个控件的完整代码,我相信不少小伙伴儿会因为字多而忽略掉。。
复制代码
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300package cc.wxf.component; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * Created by ccwxf on 2016/7/21. */ public class FlowTagView extends View { //常亮默认值,这些参数若不调用方法传递,则直接使用默认值 public static final int ROUND_RADIUS = 30; public static final int TEXT_COLOR_DEFAULT = Color.BLACK; public static final int TEXT_COLOR_SELECTED = Color.WHITE; public static final int TEXT_SIZE = 30; public static final int BACKGROUND_COLOR_DEFAULT = Color.GRAY; public static final int BACKGROUND_COLOR_SELECTED = Color.GREEN; public static final int HORIZONTAL_PADDING = 30; public static final int VERTICAL_PADDING = 30; public static final int TEXT_HORIZONTAL_PADDING = 30; public static final int ITEM_HEIGHT = 60; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private int textColorDefault = TEXT_COLOR_DEFAULT; private int textColorSelected = TEXT_COLOR_SELECTED; private int textSize = TEXT_SIZE; private int backgroundColorDefault = BACKGROUND_COLOR_DEFAULT; private int backgroundColorSelected = BACKGROUND_COLOR_SELECTED; //Tag之间的横向和纵向的间隔 private int horizontalPadding = HORIZONTAL_PADDING; private int verticalPadding = VERTICAL_PADDING; //每个Tag内部的横向间隔 private int textHorizontalPadding = TEXT_HORIZONTAL_PADDING; //每个Tag的高度 private int itemHeight = ITEM_HEIGHT; //tag的绘制起点,动态计算得值 private int startX; private int startY; //Tag显示的文本 private String[] datas; private List<Tag> tags = new ArrayList<Tag>(); //点击事件的滑动距离阈值 private int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); //ACTION_DOWN时的坐标值 private float mTouchX; private float mTouchY; //ACTION_DOWN时选中的tag的索引 private int mTouchPosition; private OnTagSelectedListener listener; public FlowTagView(Context context, AttributeSet attrs, int defStyleAttr){ super(context, attrs, defStyleAttr); } public FlowTagView(Context context, AttributeSet attrs){ super(context, attrs); } public FlowTagView(Context context){ super(context); } public FlowTagView textColor(int defaultColor, int selectedColor){ this.textColorDefault = defaultColor; this.textColorSelected = selectedColor; return this; } public FlowTagView textSize(int textSize){ this.textSize = textSize; return this; } public FlowTagView backgroundColor(int defaultColor, int selectedColor){ this.backgroundColorDefault = defaultColor; this.backgroundColorSelected = selectedColor; return this; } public FlowTagView padding(int horizontalPadding, int verticalPadding, int textHorizontalPadding){ this.horizontalPadding = horizontalPadding; this.verticalPadding = verticalPadding; this.textHorizontalPadding = textHorizontalPadding; return this; } public FlowTagView itemHeight(int height){ this.itemHeight = height; return this; } public FlowTagView datas(String[] datas){ this.datas = datas; return this; } public FlowTagView listener(OnTagSelectedListener listener){ this.listener = listener; return this; } public void commit(){ if(datas == null){ Log.e("FlowTagView", "maybe not invok the method named datas(String[])"); throw new IllegalStateException("maybe not invok the method named datas(String[])"); } paint.setTextSize(textSize); if(datas.length != tags.size()){ //重新实例化 ViewGroup.LayoutParams params = getLayoutParams(); setLayoutParams(params); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int width = MeasureSpec.getSize(widthMeasureSpec); //算出绘制起点 startX = getPaddingLeft(); startY = getPaddingTop(); tags.clear(); for(int i = 0; i < datas.length; i++){ //判断是否越过边界 if(startX + getRealWidth(paint, textSize, datas[i], textHorizontalPadding) + horizontalPadding > width - getPaddingRight()){ //在下一行开始绘制 startX = getPaddingLeft(); startY += itemHeight + verticalPadding; } Tag tag = new Tag(datas[i], textSize, textColorDefault, textColorSelected, backgroundColorDefault, backgroundColorSelected, paint, itemHeight, textHorizontalPadding, startX, startY); tags.add(tag); //动态更新值 startX += getRealWidth(paint, textSize, datas[i], textHorizontalPadding) + horizontalPadding; } //算出整个控件需要的高度 int height = startY + itemHeight + getPaddingBottom(); setMeasuredDimension(width, height); } /** * 根据参数算出某个Tag所需要占用的宽度值,包括内补白 */ public static int getRealWidth(Paint paint, int textSize, String text, int textHorizontalPadding){ paint.setTextSize(textSize); int textWidth = (int)paint.measureText(text); return textWidth + 2 * textHorizontalPadding; } @Override protected void onDraw(Canvas canvas){ //绘制代理 for(int i = 0; i < tags.size(); i++){ tags.get(i).draw(canvas); } } @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()){ case MotionEvent.ACTION_DOWN: mTouchX = event.getX(); mTouchY = event.getY(); mTouchPosition = getTagPosition(mTouchX, mTouchY); return true; case MotionEvent.ACTION_UP: float mUpX = event.getX(); float mUpY = event.getY(); //滑动距离小于点击阈值并且点击时的索引值不是非法值,并且up时的索引值和down时的索引值相等时,才触发选中操作 if(Math.abs(mUpX - mTouchX) < mTouchSlop && Math.abs(mUpY - mTouchY) < mTouchSlop && mTouchPosition != -1 && getTagPosition(mUpX, mUpY) == mTouchPosition){ //触发点击选中 setSelect(mTouchPosition); } break; } return super.onTouchEvent(event); } /** * 根本坐标值,返回对应的tag的索引,若不存在则返回-1 */ private int getTagPosition(float x, float y){ for(int i = 0; i < tags.size(); i++){ if(tags.get(i).rect.contains(x, y)){ return i; } } return -1; } public void setSelect(int position){ if(position < 0 || position >= tags.size()){ Log.e("FlowTagView", "the position is illetal"); throw new IllegalArgumentException("the position is illetal"); } for(int i = 0; i < tags.size(); i++){ //关闭其他选择 if(i != position){ tags.get(i).isSelected = false; }else{ tags.get(i).isSelected = true; } } //触发监听器 if(listener != null){ listener.onTagSelected(this, position); } //必须要刷新UI invalidate(); } public int getSelect(){ for(int i = 0; i < tags.size(); i++){ if(tags.get(i).isSelected){ return i; } } return -1; } public class Tag{ //文本属性 public String text; public int textColorDefault; public int textColorSelected; public int backgroundColorDefault; public int backgroundColorSelected; public boolean isSelected; public Paint paint; //文本的绘制起点 public int drawX; public int drawY; //整个Tag占用的坐标范围 public RectF rect = new RectF(); public Tag(String text, int textSize, int textColorDefault, int textColorSelected, int backgroundColorDefault, int backgroundColorSelected, Paint paint, int height, int horizontalPadding, int startX, int startY){ this.text = text; this.textColorDefault = textColorDefault; this.textColorSelected = textColorSelected; this.backgroundColorDefault = backgroundColorDefault; this.backgroundColorSelected = backgroundColorSelected; this.paint = paint; //求出整个Tag的宽度 paint.setTextSize(textSize); int textWidth = (int)paint.measureText(text); int width = textWidth + 2 * horizontalPadding; //计算坐标范围,startX,staryY是指左上角的起点 rect.left = startX; rect.top = startY; rect.right = startX + width; rect.bottom = startY + height; //计算居中绘制时的绘制起点 drawX = startX + horizontalPadding; Paint.FontMetrics metrics = paint.getFontMetrics(); drawY = (int)(startY + height / 2 + (metrics.bottom - metrics.top) / 2 - metrics.bottom); } public void draw(Canvas canvas){ if(isSelected){ //绘制背景 paint.setColor(backgroundColorSelected); paint.setStyle(Paint.Style.FILL); canvas.drawRoundRect(rect, ROUND_RADIUS, ROUND_RADIUS, paint); //绘制文本 paint.setColor(textColorSelected); canvas.drawText(text, drawX, drawY, paint); }else{ //绘制背景 paint.setColor(backgroundColorDefault); paint.setStyle(Paint.Style.STROKE); canvas.drawRoundRect(rect, ROUND_RADIUS, ROUND_RADIUS, paint); //绘制文本 paint.setColor(textColorDefault); canvas.drawText(text, drawX, drawY, paint); } } } public interface OnTagSelectedListener{ void onTagSelected(FlowTagView view, int position); } }
最后一段代码一定是放使用方法,这是我的习惯。。
复制代码
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"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="切换" /> <cc.wxf.component.FlowTagView android:id="@+id/tagView" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" /> </LinearLayout>
复制代码
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
65package cc.wxf.androiddemo; import android.app.Activity; import android.content.res.Resources; import android.os.Bundle; import android.view.View; import android.widget.Toast; import cc.wxf.component.FlowTagView; public class MainActivity extends Activity { private int i = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final String[] datas1 = new String[]{ "推荐", "电影", "电视剧", "头条", "娱乐", "动漫", "猜你喜欢", "资讯", "搞笑", "体育", "综艺", "片花", "少儿", "今日头条", "娱乐", "动漫", "猜你喜欢", "资讯", "搞笑", "体育", "综艺" }; final String[] datas2 = new String[]{ "推荐", "电影", "电视剧", "头条", "娱乐", "动漫", "猜你喜欢", "资讯" }; Resources resources = getResources(); final FlowTagView tagView = (FlowTagView) findViewById(R.id.tagView); tagView.datas(datas1) //下面的5个方法若不设置,则会采用默认值 .textColor(resources.getColor(android.R.color.darker_gray), resources.getColor(android.R.color.white)) .textSize(sp2px(15)) .backgroundColor(resources.getColor(android.R.color.darker_gray), resources.getColor(android.R.color.holo_green_light)) .itemHeight(dp2px(40)) .padding(dp2px(10), dp2px(10), dp2px(15)) //上面的5个方法若不设置,则会采用默认值 .listener(new FlowTagView.OnTagSelectedListener() { @Override public void onTagSelected(FlowTagView view, int position) { Toast.makeText(MainActivity.this, "选中了:" + position, Toast.LENGTH_SHORT).show(); } }) //commit必须调用 .commit(); //模拟标签的个数发生变化,造成控件的自动伸展 findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { i ++; //commit必须调用 tagView.datas(i % 2 == 0 ? datas1 : datas2).commit(); } }); } public int sp2px(int sp){ float density = getResources().getDisplayMetrics().scaledDensity; return (int) (sp * density + 0.5f); } public int dp2px(int dp){ float density = getResources().getDisplayMetrics().density; return (int) (dp * density + 0.5f); } }
Over,最后是demo的下载地址。哎,最近写博客没激情,闭关一段时间算了。
点我去下载demo
最后
以上就是勤奋美女最近收集整理的关于Android自定义流式标签控件的全部内容,更多相关Android自定义流式标签控件内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复