Dee*_*eeV 6 android android-layout android-view
我正在编写一个应用程序,其唯一目的是尝试了解Android中的视图层次结构的工作原理.我现在遇到了一些非常棘手的问题.我将在这里解释一下我的解释.
建立:
目前我有三个观点.2是ViewGroups1和1只是一个View.让我们说它们按顺序排列:
TestA extends ViewGroup
TestB extends ViewGroup
TestC extends View
TestA->TestB->TestC
Where TestC is in TestB and TestB is in TestA.
Run Code Online (Sandbox Code Playgroud)
在我看来Activity我只是这样显示视图:
TestA myView = new TestA(context);
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(myView);
Run Code Online (Sandbox Code Playgroud)
问题:
onDraw(Canvas canvas)从不调用TestA 的方法.我已经看到了一些解决方案,说我的视图没有任何尺寸(高度/宽度= 0),但事实并非如此.当我覆盖时onLayout(),我得到了布局的尺寸,它们是正确的.此外,getHeight()/ Width()完全符合它们的要求.我也可以覆盖dispatchDraw()并获取我的基本视图来绘制自己.
我想动画一个物体TestB.传统上,我会覆盖onDraw()调用方法,invalidate()直到对象完成它应该做的动画.但是,TestB当我调用invalidate()视图时,永远不会重绘.我的印象是我的父视图的工作是onDraw()再次调用该方法,但我的父视图不再调用它dispatchDraw().
我想我的问题是,为什么onDraw()我的父视图的方法永远不会被调用开始?我的父视图中的哪些方法应该在其中一个孩子使自己无效时被调用?父母负责确保孩子被吸引或者Android会照顾吗?如果Android响应invalidate(),为什么我TestB再也不会被吸引?
好吧,经过一些研究和大量的尝试,我发现我在问题#2方面做了三件事.很多都是简单的答案,但不是很明显.
您需要覆盖onMeasure()每个视图.内onMeasure(),你需要调用measure()的每一个包含在孩子ViewGroup的MeasureSpec轻描淡写地说,孩子的需求.
你需要打电话addView()给你想要包括的每个孩子.最初,我只是创建了一个视图对象并直接使用它.这允许我绘制一次,但视图不包含在视图树中,因此当我调用invalidate()它时,它不会使视图树无效而不是重绘.例如:
在testA中:
TestB childView;
TestA(Context context){
****** setup code *******
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
childView = new TestB(context);
childView.setLayoutParams(params);
}
@Override
protected void dispatchDraw(Canvas canvas){
childView.draw(canvas);
}
Run Code Online (Sandbox Code Playgroud)
这将绘制一次子视图.但是,如果该视图需要更新动画或其他内容,那就是它.我将addView(childView)TestA的构造函数添加到视图树中.最终代码是这样的:
TestB childView;
TestA(Context context){
****** setup code *******
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
childView = new TestB(context);
childView.setLayoutParams(params);
addView(childView);
}
@Override
protected void dispatchDraw(Canvas canvas){
childView.draw(canvas);
}
Run Code Online (Sandbox Code Playgroud)
或者,dispatchDraw(Canvas canvas)如果我有更多的孩子可以绘制,我可以像这样覆盖,但我需要在每个绘图之间有一些自定义元素,如网格线或其他东西.
@Override
protectd void dispatchDraw(Canvas canvas){
int childCount = getChildCount();
for(int i = 0; i < size; i++)
{
drawCustomElement();
getChildAt(i).draw(canvas);
}
}
Run Code Online (Sandbox Code Playgroud)
onLayout()(ViewGroup无论如何都是抽象的,所以无论如何它都是必需的).在这种方法中,你必须layout为每个孩子打电话.即使在完成前两件事之后,我的观点也不会失效.我一做到这一点,一切都很完美.更新: 问题#1已经解决.另一个非常简单但不那么明显的解决方案.
当我创建一个实例时TestA,我必须调用setWillNotDraw(false),否则Android将不会出于优化原因而绘制它.所以完整的设置是:
TestA myView = new TestA(context);
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
myView.setWillNotDraw(false);
setContentView(myView);
Run Code Online (Sandbox Code Playgroud)