自定义TextView——解决ViewGroup不调用OnDraw方法
2018-02-08 08:37
369 查看
首先绘制TextView继承于View:直接贴代码
源码分析为什么ViewGroup不调用onDraw,而设置背景后又可以显示自定义的TextView
首先看View中调用onDraw的源码
可以看到当dirtyOpaque为false时调用OnDraw
dirtyOpaque源码
可以看到是由privateFlags控制,即mPrivateFlags
看view的构造方法
computeOpaqueFlags();查看源码
查看ViewGroup构造方法源码
查看initViewGroup源码
可以看到最后因为setFlags的原因导致viewGrop中的OnDraw不可见。
为什么:viewgroup中设置背景后又可以显示
view中setBackDrawable的源码
此时发现又重新计算了
个人觉得解决方法可以有三
①onDraw换成dispatchDraw
②设置背景透明
③看源码可以知道设置setFlags的值即可
public class TextView extends LinearLayout{ private String mText; private int mTextSize = 18; private int mTextColor = Color.BLACK; private Paint mPaint;//文字的画笔 // 构造函数会在代码里面new的时候调用 // TextView tv = new TextView(this); public TextView(Context context) { this(context, null); } // 在布局layout中使用(调用) public TextView(Context context, AttributeSet attrs) { this(context, attrs, 0); } // 在布局layout中使用(调用),但是会有style public TextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 获取自定义属性 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TextView); mText = array.getString(R.styleable.TextView_yijiaText); mTextColor = array.getColor(R.styleable.TextView_yijiaTextColor, mTextColor); // 18 18px 18sp mTextSize = array.getDimensionPixelSize(R.styleable.TextView_yijiaTextSize, sp2px(mTextSize)); // 回收s array.recycle(); //初始化画笔 mPaint = new Paint(); mPaint.setAntiAlias(true);//设置抗锯齿 mPaint.setColor(mTextColor);//设置画笔颜色 mPaint.setTextSize(mTextSize); } /** * 自定义View的测量方法 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 布局的宽高都是由这个方法指定 // 指定控件的宽高,需要测量 // 获取宽高的模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); //1.确定的值,这个时候不需要计算,给多少是多少 int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); //2.给的是不确定值 if (widthMode == MeasureSpec.AT_MOST) { //计算的宽度 与字体的长度有关 与字体的大小 用画笔来测量 Rect rect = new Rect(); //获取文本的矩形 mPaint.getTextBounds(mText, 0, mText.length(), rect); width = rect.width(); } //2.给的是不确定值 if (heightMode == MeasureSpec.AT_MOST) { //计算的宽度 与字体的长度有关 与字体的大小 用画笔来测量 Rect rect = new Rect(); cfa7 //获取文本的矩形 mPaint.getTextBounds(mText, 0, mText.length(), rect); height = rect.height(); } setMeasuredDimension(width, height); } /** * 用于绘制 * * @param canvas */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Rect rect = new Rect(); mPaint.getTextBounds(mText, 0, mText.length(), rect); int dx = getWidth() / 2 - rect.width() / 2; //获取中心(fontMetrics.bottom - fontMetrics.top) / 2 Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; int baseLine = getHeight() / 2 + dy; canvas.drawText(mText, dx, baseLine, mPaint); Log.e("TAG", "dy==" + dy + ",centerY==" + getHeight() / 2+",baseLine=="+baseLine); } private int sp2px(int spValue) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, getResources().getDisplayMetrics()); } }
源码分析为什么ViewGroup不调用onDraw,而设置背景后又可以显示自定义的TextView
首先看View中调用onDraw的源码
// Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // Step 6, draw decorations (foreground, scrollbars) onDrawForeground(canvas);
可以看到当dirtyOpaque为false时调用OnDraw
dirtyOpaque源码
final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
可以看到是由privateFlags控制,即mPrivateFlags
看view的构造方法
computeOpaqueFlags();
computeOpaqueFlags();查看源码
// Opaque if: // - Has a background // - Background is opaque // - Doesn't have scrollbars or scrollbars overlay if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; } else { mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; } final int flags = mViewFlags; if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; } else { mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; }
查看ViewGroup构造方法源码
super(context, attrs, defStyleAttr, defStyleRes); initViewGroup(); initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
查看initViewGroup源码
if (!debugDraw()) { setFlags(WILL_NOT_DRAW, DRAW_MASK); }
可以看到最后因为setFlags的原因导致viewGrop中的OnDraw不可见。
为什么:viewgroup中设置背景后又可以显示
view中setBackDrawable的源码
computeOpaqueFlags();
if (background == mBackground) {
return;
}
此时发现又重新计算了
个人觉得解决方法可以有三
①onDraw换成dispatchDraw
②设置背景透明
③看源码可以知道设置setFlags的值即可
public void setWillNotDraw(boolean willNotDraw) { setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); }
相关文章推荐
- 自定义ViewGroup ondraw方法不被调用解决办法
- Android 自定义ViewGroup中onDraw方法不执行的解决方法
- 为什么自定义ViewGroup ondraw方法不会被调用
- 为什么自定义ViewGroup ondraw方法不会被调用
- 为什么自定义ViewGroup ondraw方法不会被调用
- 为什么自定义ViewGroup ondraw方法不会被调用
- 为什么自定义ViewGroup ondraw方法不会被调用
- textview 的onDraw()方法被重写后,文字被覆盖掉了的解决办法
- 自定义view的onDraw()方法不被调用
- 日积月累:继承ViewGroup不调用onDraw()方法
- Android中,在onAnimationEnd方法中调用 viewgroup.removeview,报 nullpointerexception异常的解决方法
- 对话框子视图Android自定义Dialog二次调用报错解决方法:The specified child already has a parent. You must call removeView()-java教程
- 自定义TextView,不执行onDraw方法,求解脱!
- ViewGroup不调用onDraw的解决办法
- 在onAnimationEnd方法中调用 viewgroup.removeview,报 nullpointerexception异常的解决方法
- 自定义view中onMeasure、onLayout、onDraw、onFinishInflate、onSizeChanged方法调用时机
- 继承 SurfaceView 无法调用到onDraw()的解决方法
- 自定义viewGroup 为什么不走 onDraw方法?
- 自定义View的onDraw(Canvas canvas)方法不被调用
- 解决listview的item为自定义viewgroup时,viewgroup子view press时,整个viewgroup都被按下的问题