闲谈自定义控件源码-view如何展示在界面上
来源:互联网 发布:python progressbar 编辑:程序博客网 时间:2024/06/07 03:32
布局是如何展示在activity上面的?
直观的看到 在activity 的oncreate(Bundle savedInstanceState)回调中的setContentView(View view)方法中设置布局。
Oncreate()回调是由谁来调用的呢?setContentView(View view)作用?
final void performCreate(Bundle icicle) {
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
由performCreate()去调用,performCreate()在何时被调用不得而知。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
通过调用成员变量window的setContentView(int resId)方法,知道phoneWindow继承自window 看PhoneWindow的源码
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
mContentParent 是用来放置DecorView或DecorView的child,如果没有装载Decorview就去装载。再看installDecor()源码
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
...
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
..
}
}
generateDecor() 创建一个DecorView,gennerateLayout()
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
...
}
应用theme 再看一下setContentView核心的一句代码:mLayoutInflater.inflate(layoutResID, mContentParent);点进去看:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
继续点进去看
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
..
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
继续点击inflate(parser, root, attachToRoot);
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
...
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
...
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
...
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
...
} catch (Exception e) {
...
} finally {
...
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return result;
}
}
看到
1:LayoutInflator 底层是通过XmlPullParser的pull解析来讲xml文件转化为java实例。
2:当遇到<merge/>标签时只会讲标签里面的子节点加入到父节点中。在写item的布局时顶层用<merge/>标签可以减少布局嵌套。
3:如果参数ViewRoot为空,attchToRoot是true和false都是没有意义的。如果ViewRoot不为空,attchToRoot为true则使用ViewRoot的LayoutParams,否则创建一个LayoutParams
0 0
- 闲谈自定义控件源码-view如何展示在界面上
- 闲谈自定义控件源码-view 坐标
- 闲谈自定义控件源码-view 测量
- 闲谈自定义控件源码-view layout draw
- 如何在fragment中获取自定义view的控件id
- 如何在fragment中获取自定义view的控件id
- 自定义 View 之炫酷的成绩展示界面
- 在 actionbarsherlock 上如何对 item 使用自定义的 view
- MFC编程中如何在工具条上实现自定义控件
- 判断View是否显示在界面上
- 移除界面上所有View、类型控件、指定控件
- 如何让自定义控件属性值更改后,值立即显示到界面上 Invalidate()
- Mac一些常用控件以及简单在自定义View上绘制字符串
- Android 如何自定义控件(继承View)
- 自定义歌词展示控件
- 自定义View,在Canvas上绘制几何图形
- 自定义Spinner在界面上的颜色
- 在froyo源码上修改Dialpad界面
- Attribute和Parameter区别
- Android 手机自动化测试工具有哪几种?
- idea gradle 配置spring boot dev-tools热部署
- Python之倒序访问list
- 结合实例与代码谈数字图像处理都研究什么?
- 闲谈自定义控件源码-view如何展示在界面上
- Windows下查看library(即.lib文件)导出函数或32、64位编译等信息的方法
- Battery Historian for windows环境搭建
- C语言结构体中定义函数指针详解
- [NODE之16]express框架response
- textarea文字换行保存到数据后读出来没有换行
- Python之修改元素
- 扑克牌的顺子
- uuid安装使用