type
status
date
slug
summary
tags
category
icon
password
设置页的处理逻辑
在
packages/apps/Settings/src/com/android/settings/development/ShowLayoutBoundsPreferenceController.java
中有:public class ShowLayoutBoundsPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String DEBUG_LAYOUT_KEY = "debug_layout"; public ShowLayoutBoundsPreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return DEBUG_LAYOUT_KEY; } // 当用户切换选项的时候,通过IBinder通知到各种服务 @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean isEnabled = (Boolean) newValue; DisplayProperties.debug_layout(isEnabled); SystemPropPoker.getInstance().poke(); return true; } @Override public void updateState(Preference preference) { final boolean isEnabled = DisplayProperties.debug_layout().orElse(false); ((SwitchPreference) mPreference).setChecked(isEnabled); } @Override protected void onDeveloperOptionsSwitchDisabled() { super.onDeveloperOptionsSwitchDisabled(); DisplayProperties.debug_layout(false); ((SwitchPreference) mPreference).setChecked(false); } }
DisplayProperties是生成的类,看一下其中的debug_layout属性:
public static void debug_layout(Boolean value) { SystemProperties.set("debug.layout", value == null ? "" : value.toString()); }
Android系统属性定义在
.sysprop
文件中,其本质上是一个protobuf文件.看一下debug_layout属性(
system/libsysprop/srcs/android/sysprop/DisplayProperties.sysprop
中):prop { api_name: "debug_layout" type: Boolean scope: Internal access: ReadWrite prop_name: "debug.layout" }
然后系统会自动生成一些中间类.比如上面的DisplayProperties.java.
总结一下,其实就是:
- 系统属性定义在
.sysprop
文件中,系统会自动生成一些中间类用于读写属性
- 设置页中用户打开/关闭开关,会改变属性值,然后通过Binder机制通知给各个服务;
debug.layout运行机制
在ViewRootImpl初始化的时候会执行下面的方法:
public void loadSystemProperties() { mHandler.post(new Runnable() { @Override public void run() { // ... // Layout debugging boolean layout = DisplayProperties.debug_layout().orElse(false); if (layout != mAttachInfo.mDebugLayout) { mAttachInfo.mDebugLayout = layout; if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); } } } }); } // 自身以及其子View全部都重新绘制 void invalidateWorld(View view) { view.invalidate(); if (view instanceof ViewGroup) { ViewGroup parent = (ViewGroup) view; for (int i = 0; i < parent.getChildCount(); i++) { invalidateWorld(parent.getChildAt(i)); } } }
在View的draw中有下面这一句:
if (isShowingLayoutBounds()) { debugDrawFocus(canvas); } final private void debugDrawFocus(Canvas canvas) { if (isFocused()) { final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); final int l = mScrollX; final int r = l + mRight - mLeft; final int t = mScrollY; final int b = t + mBottom - mTop; final Paint paint = getDebugPaint(); paint.setColor(DEBUG_CORNERS_COLOR); // Draw squares in corners. paint.setStyle(Paint.Style.FILL); // 左 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); // 右 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); // 下 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); // 上 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); // 绘制一个View上的大X paint.setStyle(Paint.Style.STROKE); canvas.drawLine(l, t, r, b, paint); canvas.drawLine(l, b, r, t, paint); } }
上面这些就是我们看到的那些红色框框的绘制逻辑了.
adb获取系统属性
- 获取全部属性
adb shell getprop
- 获取指定属性
adb shell getprop debug.layout
adb打开关闭“显示布局边界”
adb shell setprop debug.layout true adb shell setprop debug.layout false
执行完命令之后要重启APP才会看到效果.
- 作者:姜康
- 链接:https://jiangkang.tech/article/d05d62c9-9e97-4f6b-8f7f-551586806c51
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章