背景
在日常开发中我们经常会遇到需要展示多个TextView控件。因为TextView控件个数的不确定,下面就需要我们用到动态创建来解决,顺便也讲解下因为TextView控件过多自动换行排列这种情况。
效果图
效果图实现
1.首先我们需要在xml中定义一个父布局,并且设置上ID,并且在Activity中进行初始化。
<LinearLayout
android:id="@+id/ll_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"/>
// 初始化父布局(LinearLayout)线性布局
LinearLayout linearLayout = findViewById(R.id.ll_one);
2.为了模拟TextView个数较多,这里我们用for循环创建TextView。并且设置TextView的属性来保证TextView在父View中位置。
//设置TextView的属性
RelativeLayout.LayoutParams lps = new RelativeLayout.LayoutParams(WRAP_CONTENT,WRAP_CONTENT);
lps.setMargins(20,20,20,20);
for (int i = 0; i < 50; i++) {
TextView textView = new TextView(this);
textView.setText(getName());
textView.setTextColor(mColorList.get(rdColor.nextInt(8)));
textView.setPadding(20,20,20,20);
textView.setBackground(getDrawable(R.drawable.shape_edit));
textView.setLayoutParams(lps);
linearLayout.addView(textView);
}
3.为了需要50个模拟数据,这里我用到Random,用来随机获取50个姓名。
public String getName() {
Random random = new Random();
String[] Surname = {"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋", "沈", "韩", "杨", "朱", "秦", "尤", "许",
"何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏", "陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭", "郎",
"鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "俞", "任", "袁", "柳", "酆", "鲍", "史", "唐", "费", "廉", "岑", "薛", "雷", "贺", "倪", "汤", "滕", "殷",
"罗", "毕", "郝", "邬", "安", "常", "乐", "于", "时", "傅", "皮", "卞", "齐", "康", "伍", "余", "元", "卜", "顾", "孟", "平", "黄", "和",
"穆", "萧", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "禹", "狄", "米", "贝", "明", "臧", "计", "伏", "成", "戴", "谈", "宋", "茅", "庞", "熊", "纪", "舒",
"屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "席", "季"};
String girl = "秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊兰凤洁梅琳素云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜可姬舒影荔枝思丽 ";
String boy = "伟刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘";
int index = random.nextInt(Surname.length - 1);
//获得一个随机的姓氏
String name = Surname[index];
//可以根据这个数设置产生的男女比例
int i = random.nextInt(3);
if(i==2){
int j = random.nextInt(girl.length()-2);
if (j % 2 == 0) {
name = "女-" + name + girl.substring(j, j + 2);
} else {
name = "女-" + name + girl.substring(j, j + 1);
}
}
else{
int j = random.nextInt(girl.length()-2);
if (j % 2 == 0) {
name = "男-" + name + boy.substring(j, j + 2);
} else {
name = "男-" + name + boy.substring(j, j + 1);
}
}
return name;
}
4.到此,动态创建TextView已经结束,但是细心的小伙伴已经发现50个TextViewhorizontal(水平)
排列在手机屏幕上肯定会有很多名字没有展示。没错!这个时候就需要我们自定义换行控件了。二话不说先上代码:
public class HorizantalAutoBrLayout extends ViewGroup {
/**
* 可使用的最大宽度
*/
private int maxWidth;
public HorizantalAutoBrLayout (Context context) {
super(context);
}
public HorizantalAutoBrLayout (Context context, AttributeSet attrs) {
super(context, attrs);
}
public HorizantalAutoBrLayout (Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
maxWidth = MeasureSpec.getSize(widthMeasureSpec);
/**
* 容器的高度,也就是本布局的高度。初始化赋值为0.
*/
int containorHeight = 0;
/**
* 获取该布局内子组件的个数
*/
int count = getChildCount();
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
/**
* measure(int widthMeasureSpec,int
* heightMeasureSpec)用于设置子组件显示模式.有三个值:
* MeasureSpec.AT_MOST 该组件可以设置自己的大小,但是最大不能超过其父组件的限定
* MeasureSpec.EXACTLY 无论该组件设置大小是多少,都只能按照父组件限制的大小来显示
* MeasureSpec.UNSPECIFIED 该组件不受父组件的限制,可以设置任意大小
*/
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
// 把每个子组件的高度相加就是该组件要显示的高度。
containorHeight += view.getMeasuredHeight();
}
/**
* onMeasure方法的关键代码,该句设置父容器的大小。
*/
setMeasuredDimension(maxWidth, containorHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 获取子组件数
int childCount = getChildCount();
// 子组件行数,初始化赋值为1
int row = 1;
// 子组件的左边“坐标”
int left = 0;
// 子组件的右边“坐标”
int right = 0;
// 子组件的顶部“坐标”
int top = 0;
// 子组件的底部“坐标”
int bottom = 0;
// 在父组件中设置的padding属性的值,该值显然也会影响到子组件在屏幕的显示位置
int p = getPaddingLeft();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
// 测量子组件的宽
int width = view.getMeasuredWidth();
// 测量子组件的高
int height = view.getMeasuredHeight();
left = p + right;
right = left + width;
top = p * row + height * (row - 1);
bottom = top + height;
if (right > maxWidth) {
row++;
//每次换行后要将子组件左边“坐标”与右边“坐标”重新初始化
left = 0;
right = 0;
left = p + right;
right = left + width;
top = p * row + height * (row - 1);
bottom = top + height;
}
// 最后按照计算出来的“坐标”将子组件放在父容器内
view.layout(left, top, right, bottom);
}
}
}
5.这里自定义自动换行控件的思路就是在首先确定父容器的宽高,然后在测量每个子view的宽高,比较屏幕的宽来确定是否换行。
6.最后我们需要将xml中的LinearLayout,换成我们自定义的HorizantalAutoBrLayout
。
<com.example.textviewmovedemo.view.HorizantalAutoBrLayout
android:id="@+id/ll_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"/>
7.对了有些朋友会问到你的每个TextView的颜色是怎么设置的,这里我的思路是创建一个colorList(颜色集合),向颜色集合中添加8种不同的颜色,然后通过Random来随机取出使用。
Random rdColor =new Random();
List<Integer> mColorList = new ArrayList<>();
mColorList.add(Color.BLUE);
mColorList.add(Color.RED);
mColorList.add(Color.GRAY);
mColorList.add(Color.BLACK);
mColorList.add(Color.GREEN);
mColorList.add(Color.LTGRAY);
mColorList.add(Color.DKGRAY);
mColorList.add(Color.MAGENTA);
textView.setTextColor(mColorList.get(rdColor.nextInt(8)));
如果有特殊情况处理不了的可以留言
好了,到此结束了。希望用的小伙伴帮忙点下赞,谢谢~
网友评论