【原创】【Andriod】自定义多行多列视图
【需求描述】最近要开发一个文本视图组件,满足如下几种样式:
case 1: 三行两列,第一列的文字字数一样多
case 2: 三行两列,第一列的文字字数不一样多,第一列的右边线与第二列的左边线的间距是一定的,第二列里的每一项,可能有1~3行
case 3: 可能有1~3行
总结一下特点:
1)第一列左对齐(每一项为单行文字),第二列左对齐(每一项为1~3行文字)
2)第二列距离第一列的最小间距是固定值
3)第一列第一条与第二列第一条顶对齐,以此类推,第一列第二条与第二列第二条顶对齐……
【技术方案】
方案1:定义一个LinearLayout, 根据第一列文本的size和下发的文本来计算第一列的最大宽度,计算完成后,动态添加1~3个FrameLayout,1个FrameLayout中放每一行的子元素
方案2:定义一个FrameLayout,根据第一列文本的size和下发的文本来计算第一列的最大宽度,然后计算出每一项的高度,分别对每个子元素进行布局。
优点 | 缺点 | |
方案1 | 方案简单,将每一行元素的高度计算交给FrameLayout | 会多3个FrameLayout,需要多Measure和layout 3次 |
方案2 | 布局层次少,性能更优 | 需要考虑第二列的多行文本的高度计算 |
方案1 核心代码如下:
1 /** 2 * 获取文本的长度 3 * 4 * @param displayText 待显示的文本 5 * @return 6 */ 7 private int getTextLength(String displayText) { 8 Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 9 mTextPaint.setColor(getContext().getResources() 10 .getColor(R.color.msg_pay_notify_producer_name_key_color)); 11 mTextPaint.setTextSize(getContext().getResources().getDimensionPixelSize( 12 R.dimen.msg_pay_notify_producer_name_size)); 13 return (int) mTextPaint.measureText(displayText); 14 } 15 16 17 1、计算第一列的最大宽度 18 ArrayList<String> displayLists = new ArrayList<>(); 19 for (PayCardModel.BodyItem item : bodys) { 20 displayLists.add(item.getMName()); 21 } 22 23 mFirstColumnWidth = 0; 24 for (String displayText : displayLists) { 25 mFirstColumnWidth = Math.max(mFirstColumnWidth, getTextLength(displayText)); 26 } 27 28 if (mFirstColumnWidth == 0) { 29 setVisibility(GONE); 30 return; 31 } 32 setVisibility(VISIBLE); 33 mFirstColumnWidth = mFirstColumnWidth > MAX_FIRST_COLUMN_WIDTH ? 34 MAX_FIRST_COLUMN_WIDTH : mFirstColumnWidth; 35 mSecColumnLeftMargin = mFirstColumnWidth + getContext().getResources() 36 .getDimensionPixelSize(R.dimen.msg_pay_notify_producer_name_margin_left); 37 38 39 2、动态添加子元素 40 /** 41 * 构造每一对数据需要的两个TextView 42 * 43 * @param item 数据对 44 * @return 45 */ 46 private ViewGroup buildItemViews(PayCardModel.BodyItem item) { 47 if (!isDataValid(item)) { 48 return null; 49 } 50 FrameLayout layout = new FrameLayout(getContext()); 51 LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 52 ViewGroup.LayoutParams.WRAP_CONTENT); 53 TextView titleView = new TextView(getContext()); 54 titleView.setText(item.getMName()); 55 titleView.setTextColor(getContext().getResources() 56 .getColor(R.color.msg_pay_notify_producer_name_key_color)); 57 titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 58 getContext().getResources().getDimensionPixelSize( 59 R.dimen.msg_pay_notify_producer_name_size)); 60 titleView.setMaxLines(MAX_TITLE_LINE); 61 titleView.setMaxEms(MAX_TITLE_EMS); 62 FrameLayout.LayoutParams titleParams = new FrameLayout.LayoutParams(mFirstColumnWidth, 63 ViewGroup.LayoutParams.WRAP_CONTENT); 64 layout.addView(titleView, titleParams); 65 66 TextView view = new TextView(getContext()); 67 view.setText(item.getMValue()); 68 view.setTextColor(getContext().getResources() 69 .getColor(R.color.msg_pay_notify_source_color)); 70 view.setTextSize(TypedValue.COMPLEX_UNIT_PX, 71 getContext().getResources().getDimensionPixelSize( 72 R.dimen.msg_pay_notify_producer_name_size)); 73 view.setMaxLines(MAX_NAME_LINE); 74 view.setEllipsize(TextUtils.TruncateAt.END); 75 FrameLayout.LayoutParams viewParams = new FrameLayout.LayoutParams( 76 ViewGroup.LayoutParams.WRAP_CONTENT, 77 ViewGroup.LayoutParams.WRAP_CONTENT); 78 viewParams.leftMargin = mSecColumnLeftMargin; 79 layout.addView(view, viewParams); 80 addView(layout, layoutParams); 81 return layout; 82 }