本文共 5985 字,大约阅读时间需要 19 分钟。
上篇已经实现了条件换行的自定义VIew,最后也说到onLayout来设置换行显示,这里用ViewGroup来实现,无非canvas.drawText控制文字换行换成onLayout来控制textview的换行。
既然是ViewGroup,那里面装的就是View了,这里使用上篇自定义的textview,因为系统的Textview是有行距的。
首先,onMeasure还是会首先执行,你可以使用自定义View时候的方法来计算宽高(文字大小+padding)+viewgroup的padding,也可以直接得到子View的宽高,然后加上padding。 得到子view的个数: int hadChildCount = getChildCount(); 得到子view的实例: View child = getChildAt(i); 计算子view的宽高等: measureChild(child, widthMeasureSpec, heightMeasureSpec); 得到子view的宽高:int childMeasuredHeight = child.getMeasuredHeight(); onMeasure已经得到了当前viewgroup的所有view,现在需要对子view的位置进行排布 使用View.layout(left,top,right,bottom)设置位置即可:四个点确定一个矩形范围效果图:
实例代码如下:
public class MyTextview_Viewgroup extends ViewGroup { public MyTextview_Viewgroup(Context context) { super(context); } public MyTextview_Viewgroup(Context context, AttributeSet attrs) { super(context, attrs); initAtters(context, attrs); } public MyTextview_Viewgroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAtters(context, attrs); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public MyTextview_Viewgroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initAtters(context, attrs); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int startLeft = getPaddingLeft(); int startTop = getPaddingTop(); int startRight = getPaddingLeft(); int startBottom = getPaddingTop(); for (int i = 0; i < childs.size(); i++) { View child = childs.get(i); startRight = startRight + child.getMeasuredWidth(); startBottom = startBottom + child.getMeasuredHeight(); //left top right bottom child.layout(startLeft, startTop, startRight, startBottom); startTop = startTop + child.getMeasuredHeight(); } } String text = "需要显示的文字"; private void initAtters(Context context, @Nullable AttributeSet attrs) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyTextview); text = array.getString(R.styleable.MyTextview_texcontent); } private void initView(int widthSize) { //因为onmeasure会执行多次 this.removeAllViews(); //首先还是判断能不能一行放下 Paint paint = null; Rect rect = null; if (paint == null) { paint = new Paint(); paint.setTextSize(SizeUtil.sp2px(getContext(), 20.0f)); paint.setColor(Color.parseColor("#000000")); paint.setAntiAlias(true); paint.setFilterBitmap(true);//位图过滤 ; } if (rect == null) { rect = new Rect(); } paint.getTextBounds(text, 0, text.length(), rect); // if (widthSize - getPaddingLeft() - getPaddingRight() >= rect.width()) { //一行容纳 MyTextview textView = new MyTextview(getContext()); textView.setPadding(0, 0, 0, 0); ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); textView.setLayoutParams(layoutParams); textView.setText(text); this.addView(textView); return; } ListrowStrings = new ArrayList<>(); double rows = text.length() / 7.0; int lineNum = (int) Math.ceil(rows); //一行文字所包含的文字数 //0开始,依次加然后判断 for (int i = 0; i < lineNum; i++) { String rowText = ""; if (i == lineNum - 1) { rowStrings.add(text.substring(i * 7, text.length())); rowText = text.substring(i * 7, text.length()); } else { rowStrings.add(text.substring(i * 7, (i + 1) * 7)); rowText = text.substring(i * 7, (i + 1) * 7); } MyTextview textView = new MyTextview(getContext()); textView.setPadding(0, 0, 0, 0); ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); textView.setLayoutParams(layoutParams); textView.setText(rowText); this.addView(textView); } } List childs; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); childs = new ArrayList<>(); // Log.e("MyViewgroup+onMeasure", "现在有多少个子view" + getChildCount()); int widthMode = MeasureSpec.getMode(widthMeasureSpec); //获取宽的模式 int heightMode = MeasureSpec.getMode(heightMeasureSpec); //获取高的模式 int widthSize = MeasureSpec.getSize(widthMeasureSpec); //获取宽的尺寸 int heightSize = MeasureSpec.getSize(heightMeasureSpec); //获取高的尺寸 initView(widthSize); //测量子view的宽高,然后得到整个的宽高 int width = 0; int height = 0; int hadChildCount = getChildCount(); for (int i = 0; i < hadChildCount; i++) { View child = getChildAt(i); childs.add(child); //测量下子view的大小 measureChild(child, widthMeasureSpec, heightMeasureSpec); int childMeasuredHeight = child.getMeasuredHeight(); int childMeasuredWidth = child.getMeasuredWidth(); // Log.e("当前child的宽和高是", childMeasuredWidth + "-" + childMeasuredHeight); if (childMeasuredWidth > width) { width = childMeasuredWidth + getPaddingLeft() + getPaddingRight(); } height = height + childMeasuredHeight; } if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } //保存测量宽度和测量高度 setMeasuredDimension(width, height + getPaddingBottom() + getPaddingTop()); Log.e("计算出来viewgroup的高度是", height + getPaddingTop() + getPaddingBottom() + ""); }}
转载地址:http://scrci.baihongyu.com/