1. 自定义TextView继承View文字可以显示,继承ViewGroup(LinearLayout)不显示?
继承LinearLayout,如果在 activity_mytextview 中设置background,文字可以显示,不设置background文字就不能显示;
ViewGroup默认不调用onDraw
原因是:LinearLayout继承ViewGroup,ViewGroup继承View,在view中有 draw(),所以自定义TextView的onDraw其实调用的是 draw中的方法,draw用的是模板设计模式,如下:
if (!dirtyOpaque) onDraw(canvas);
dispatchDraw(canvas);
onDrawForeground
public void draw(Canvas canvas){
// 由这里可知,这里需要知道 mPrivateFlags 在哪里赋值的
final int privateFlags = mPrivateFlags;
// dirtyOpaque
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
// dirtyOpaque为 false,会调用 onDraw
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
}
dirtyOpaque为false,会调用onDraw
// View构造方法
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
computeOpaqueFlags();
}
protected void 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构造方法中的 initViewGroup()
private void initViewGroup() {
if (!debugDraw()) {
// 这个是View中的 setFlag,默认不画任何东西
setFlags(WILL_NOT_DRAW, DRAW_MASK);
}
}
在draw()构造方法中调用 computeOpaqueFlags,ViewGroup中不能显示TextView,因为在ViewGroup中的构造方法中会调用 initViewGroup,这个方法中的 setFlags(WILL_NOT_DRAW, DRAW_MASK) 中的 WILL_NOT_DRAW默认不画任何东西,进不去 if (!dirtyOpaque) onDraw(canvas),所以不能显示;
在布局文件中设置background,就能显示,是因为在 xml文件中设置 background后,会调用 setBackgroundDrawable(),在该方法中会调用 computeOpaqueFlags重新计算,所以TextView会显示;
// 在xml中设置 background后,会调用 setBackgroundDrawable
@Deprecated
public void setBackgroundDrawable(Drawable background) {
// 重新调用 computeOpaqueFlags,会去重新计算
computeOpaqueFlags();
}
TextView继承LinearLayout,在xml中,不设置background,还想要让TextView显示,可以用如下方式:
1>:把 onDraw 改为 dispatchDraw;
2>:如果在xml中没有设置 background,直接在 第三个构造方法中设置 透明背景;
3>:在第三个构造方法中写 setWillNotDraw(false);
代码已上传至github
https://github.com/shuai999/View_day02.git
2. Activity的启动流程及有时候获取TextView高度获取不到原因分析?
public class MainActivity extends AppCompatActivity {
private TextView text_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_view = (TextView) findViewById(R.id.text_view);
Log.e("TAG" , "height1 -> "+text_view.getMeasuredHeight()) ; //height1 -> 0
//这种情况是不能获取view高度的 , 因为传递的null,父布局为null
View view = View.inflate(this , R.layout.activity_main , null) ;
//这种情况是可以获取view高度的 , 需要传递ViewGroup ,
// View view = View.inflate(this , R.layout.activity_main , text_view) ;
text_view.post(new Runnable() {
//只是把Runnable保存到queue<队列>中,什么都没干,会在dispatchAttachedToWindow中执行,而这个方法会在测量完毕后调用,然后在这个方法的下边会执行executeActions()
@Override
public void run() {
Log.e("TAG" , "height2 -> "+text_view.getMeasuredHeight()) ; //height2 -> 1710
}
}) ;
}
@Override
protected void onResume() {
super.onResume();
Log.e("TAG" , "height3 -> "+text_view.getMeasuredHeight()) ; //height3 -> 0
}
}
结果如下:
height1 -> 高度为0:onCreate中调用 setContentView,而 setContentView中只是创建 DecorView对象,然后把 setContentView的布局 添加到 DecorView中,没有调用 onMeasure,所以高度为0;
height3 -> 高度为0:由Activity启动流程知:performLaunchActivity__onResume,没有调用 onMeasure,所以高度为0;
网友评论