【发布时间】:2018-02-20 04:45:40
【问题描述】:
为了理解 Android 上的Double Taxation,我编写了以下非常简单的代码。有一个RelativeLayout 和三个TextViews。
<?xml version="1.0" encoding="utf-8"?>
<ru.maksim.sample_app.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="ru.maksim.sample_app.MainActivity">
<ru.maksim.sample_app.MyTextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fca"
android:tag="text1"
android:text="Text 1" />
<ru.maksim.sample_app.MyTextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text1"
android:background="#acf"
android:tag="text2"
android:text="Text 2" />
<ru.maksim.sample_app.MyTextView
android:id="@+id/text3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text1"
android:layout_toRightOf="@id/text2"
android:background="#fac"
android:tag="text3"
android:text="text 3" />
</ru.maksim.sample_app.MyRelativeLayout>
MyTextView
public class MyTextView extends android.support.v7.widget.AppCompatTextView {
private static final String TAG = "MyTextView";
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context,
@Nullable AttributeSet attrs
) {
super(context, attrs);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
Log.d(TAG,
"onMeasure, "
+ getTag()
+ " widthMeasureSpec=" + MeasureSpecMap.getName(widthMode)
+ " heightMeasureSpec=" + MeasureSpecMap.getName(heightMode)
);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG, getTag() + " onLayout");
}
}
MyRelativeLayout
public class MyRelativeLayout extends RelativeLayout {
public static final String TAG = "MyRelativeLayout";
public MyRelativeLayout(Context context) {
super(context);
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
Log.d(TAG,
"onMeasure, "
+ getTag()
+ " widthMeasureSpec=" + MeasureSpecMap.getName(widthMode)
+ " heightMeasureSpec=" + MeasureSpecMap.getName(heightMode)
);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG, getTag() + " onLayout");
}
}
Logcat:
09-11 19:25:40.077 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text2 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text3 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text3 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text2 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.078 7732-7732/ru.maksim.sample_app D/MyRelativeLayout: onMeasure, null widthMeasureSpec=EXACTLY heightMeasureSpec=EXACTLY
[ 09-11 19:25:40.098 7732: 7748 D/ ]
HostConnection::get() New Host Connection established 0xa0a8fbc0, tid 7748
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text2 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text3 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text3 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: onMeasure, text2 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyRelativeLayout: onMeasure, null widthMeasureSpec=EXACTLY heightMeasureSpec=EXACTLY
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: text1 onLayout
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: text2 onLayout
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyTextView: text3 onLayout
09-11 19:25:40.132 7732-7732/ru.maksim.sample_app D/MyRelativeLayout: null onLayout
现在让我们将MyRelativeLayout 替换为LinearLayoiut 的子代MyLinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<ru.maksim.sample_app.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="ru.maksim.sample_app.MainActivity">
<ru.maksim.sample_app.MyTextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fca"
android:tag="text1"
android:text="Text 1" />
<ru.maksim.sample_app.MyTextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#acf"
android:tag="text2"
android:text="Text 2" />
<ru.maksim.sample_app.MyTextView
android:id="@+id/text3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fac"
android:tag="text3"
android:text="text 3" />
</ru.maksim.sample_app.MyLinearLayout>
MyLinearLayout
public class MyLinearLayout extends LinearLayout {
public static final String TAG = "MyLinearLayout";
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
Log.d(TAG,
"onMeasure, "
+ getTag()
+ " widthMeasureSpec=" + MeasureSpecMap.getName(widthMode)
+ " heightMeasureSpec=" + MeasureSpecMap.getName(heightMode)
);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG, getTag() + " onLayout");
}
}
这是我现在在 logcat 中看到的内容:
09-11 19:50:57.974 2781-2781/? D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:50:57.974 2781-2781/? D/MyTextView: onMeasure, text2 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:50:57.974 2781-2781/? D/MyTextView: onMeasure, text3 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:50:57.974 2781-2781/? D/MyLinearLayout: onMeasure, null widthMeasureSpec=EXACTLY heightMeasureSpec=EXACTLY
[ 09-11 19:50:58.004 2781: 2817 D/ ]
HostConnection::get() New Host Connection established 0xa5ec1940, tid 2817
09-11 19:50:58.017 2781-2781/? D/MyTextView: onMeasure, text1 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:50:58.017 2781-2781/? D/MyTextView: onMeasure, text2 widthMeasureSpec=AT_MOST heightMeasureSpec=AT_MOST
09-11 19:50:58.017 2781-2781/? D/MyTextView: onMeasure, text3 widthMeasureSpec=EXACTLY heightMeasureSpec=AT_MOST
09-11 19:50:58.017 2781-2781/? D/MyLinearLayout: onMeasure, null widthMeasureSpec=EXACTLY heightMeasureSpec=EXACTLY
09-11 19:50:58.017 2781-2781/? D/MyTextView: text1 onLayout
09-11 19:50:58.017 2781-2781/? D/MyTextView: text2 onLayout
09-11 19:50:58.017 2781-2781/? D/MyTextView: text3 onLayout
09-11 19:50:58.017 2781-2781/? D/MyLinearLayout: null onLayout
以上两个示例中使用的MeasureSpecMap 仅包含以下Map:
public class MeasureSpecMap {
private static final Map<Integer, String> MAP = new HashMap<>();
static {
MAP.put(View.MeasureSpec.AT_MOST, "AT_MOST");
MAP.put(View.MeasureSpec.EXACTLY, "EXACTLY");
MAP.put(View.MeasureSpec.UNSPECIFIED, "UNSPECIFIED");
}
private MeasureSpecMap() {
}
public static String getName(int mode) {
return MAP.get(mode);
}
}
问题 1。
在使用MyRelativeLayout时,为什么系统需要在调用MyRelativeLayout的onMeasure之前对每个孩子调用onMeasure两次?使用MyLinearLayout,我的示例中的每个孩子都被测量一次,如您在上面的日志输出中所见。
问题 2。
这是来自the Double taxation section 的我不明白的其他内容:
当您使用 RelativeLayout 容器时,它允许您 位置视图对象相对于其他视图的位置 对象,框架执行以下操作:
执行布局和测量过程,在此过程中框架 根据每个子对象计算每个子对象的位置和大小 孩子的要求。使用此数据,同时将对象权重纳入 帐户,找出相关视图的正确位置。
使用此数据,同时考虑对象权重,找出 相关视图的正确位置。
但是等等……他们不是在谈论android:layout_weight,这是LinearLayout 的一个功能吗?
上面的代码也可以在 GitHub 上找到:
【问题讨论】:
-
问题 #2 的答案:可能是文档错误。
标签: android android-layout layout android-linearlayout android-relativelayout