《设计思想解读开源框架》
第一章、 热修复设计
-
第一节、 AOT/JIT & dexopt 与 dex2oat
-
第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题
-
第三节、热修复设计之热修复原理
-
第四节、Tinker 的集成与使用(自动补丁包生成)
第二章、 插件化框架设计
-
第一节、 Class 文件与 Dex 文件的结构解读
-
第二节、 Android 资源加载机制详解
-
第三节、 四大组件调用原理
-
第四节、 so 文件加载机制
-
第五节、 Android 系统服务实现原理
第三章、 组件化框架设计
-
第一节、阿里巴巴开源路由框——ARouter 原理分析
-
第二节、APT 编译时期自动生成代码&动态类加载
-
第三节、 Java SPI 机制
-
第四节、 AOP&IOC
-
第五节、 手写组件化架构
第四章、图片加载框架
-
第一节、图片加载框架选型
-
第二节、Glide 原理分析
-
第三节、手写图片加载框架实战
第五章、网络访问框架设计
-
第一节、网络通信必备基础
-
第二节、OkHttp 源码解读
-
第三节、Retrofit 源码解析
第六章、 RXJava 响应式编程框架设计
-
第一节、链式调用
-
第二节、 扩展的观察者模式
-
第三节、事件变换设计
-
第四节、Scheduler 线程控制
第七章、 IOC 架构设计
-
第一节、 依赖注入与控制反转
-
第二节、ButterKnife 原理上篇、中篇、下篇
-
第三节、Dagger 架构设计核心解密
第八章、 Android 架构组件 Jetpack
-
第一节、 LiveData 原理
-
第二节、 Navigation 如何解决 tabLayout 问题
-
第三节、 ViewModel 如何感知 View 生命周期及内核原理
-
第四节、 Room 架构方式方法
-
第五节、 dataBinding 为什么能够支持 MVVM
-
第六节、 WorkManager 内核揭秘
-
第七节、 Lifecycles 生命周期
本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
2、onMeasure
在onMeasure中计算childView的测量值以及模式,以及设置自己的宽和高:
/**
- 计算所有ChildView的宽度和高度 然后根据ChildView的计算结果,设置自己的宽和高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
/**
- 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
// 计算出所有的childView的宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec);
/**
- 记录如果是wrap_content是设置的宽和高
*/
int width = 0;
int height = 0;
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
MarginLayoutParams cParams = null;
// 用于计算左边两个childView的高度
int lHeight = 0;
// 用于计算右边两个childView的高度,最终高度取二者之间大值
int rHeight = 0;
// 用于计算上边两个childView的宽度
int tWidth = 0;
// 用于计算下面两个childiew的宽度,最终宽度取二者之间大值
int bWidth = 0;
/**
- 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时
*/
for (int i = 0; i < cCount; i++)
{
View childView = getChildAt(i);
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
cParams = (MarginLayoutParams) childView.getLayoutParams();
// 上面两个childView
if (i == 0 || i == 1)
{
tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
}
if (i == 2 || i == 3)
{
bWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
}
if (i == 0 || i == 2)
{
lHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
}
if (i == 1 || i == 3)
{
rHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
}
}
width = Math.max(tWidth, bWidth);
height = Math.max(lHeight, rHeight);
/**
-
如果是wrap_content设置为我们计算的值
-
否则:直接设置为父容器计算的值
*/
-
setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
-
width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
-
height);
}
10-14行,获取该ViewGroup父容器为其设置的计算模式和尺寸,大多情况下,只要不是wrap_content,父容器都能正确的计算其尺寸。所以我们自己需要计算如果设置为wrap_content时的宽和高,如何计算呢?那就是通过其childView的宽和高来进行计算。
17行,通过ViewGroup的measureChildren方法为其所有的孩子设置宽和高,此行执行完成后,childView的宽和高都已经正确的计算过了
43-71行,根据childView的宽和高,以及margin,计算ViewGroup在wrap_content时的宽和高。
80-82行,如果宽高属性值为wrap_content,则设置为43-71行中计算的值,否则为其父容器传入的宽和高。
3、onLayout对其所有childView进行定位(设置childView的绘制区域)
// abstract method in viewgroup
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
MarginLayoutParams cParams = null;
/**
- 遍历所有childView根据其宽和高,以及margin进行布局
*/
for (int i = 0; i < cCount; i++)
{
View childView = getChildAt(i);
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
cParams = (MarginLayoutParams) childView.getLayoutParams();
int cl = 0, ct = 0, cr = 0, cb = 0;
switch (i)
{
case 0:
cl = cParams.leftMargin;
ct = cParams.topMargin;
break;
case 1:
cl = getWidth() - cWidth - cParams.leftMargin
- cParams.rightMargin;
ct = cParams.topMargin;
break;
case 2:
cl = cParams.leftMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
case 3:
cl = getWidth() - cWidth - cParams.leftMargin
- cParams.rightMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
}
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout(cl, ct, cr, cb);
}
}
代码比较容易懂:遍历所有的childView,根据childView的宽和高以及margin,然后分别将0,1,2,3位置的childView依次设置到左上、右上、左下、右下的位置。
如果是第一个View(index=0) :则childView.layout(cl, ct, cr, cb); cl为childView的leftMargin , ct 为topMargin , cr 为cl+ cWidth , cb为 ct + cHeight
如果是第二个View(index=1) :则childView.layout(cl, ct, cr, cb);
cl为getWidth() - cWidth - cParams.leftMargin- cParams.rightMargin;
ct 为topMargin , cr 为cl+ cWidth , cb为 ct + cHeight
剩下两个类似~
这样就完成了,我们的ViewGroup代码的编写,下面我们进行测试,分别设置宽高为固定值,wrap_content,match_parent
5、测试结果
布局1:
<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“200dp”
android:layout_height=“200dp”
android:background=“#AA333333” >
<TextView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“#FF4444”
android:gravity=“center”
android:text=“0”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
<TextView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“#00ff00”
android:gravity=“center”
android:text=“1”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
<TextView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“#ff0000”
android:gravity=“center”
android:text=“2”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
<TextView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“#0000ff”
android:gravity=“center”
android:text=“3”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
</com.example.zhy_custom_viewgroup.CustomImgContainer>
ViewGroup宽和高设置为固定值
效果图:
布局2:
<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:background=“#AA333333” >
<TextView
android:layout_width=“150dp”
android:layout_height=“150dp”
android:background=“#E5ED05”
android:gravity=“center”
android:text=“0”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
<TextView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“#00ff00”
android:gravity=“center”
android:text=“1”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
最后
在此为大家准备了四节优质的Android高级进阶视频:
架构师项目实战——全球首批Android开发者对Android架构的见解
附相关架构及资料
往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
gravity=“center”
android:text=“1”
android:textColor=“#FFFFFF”
android:textSize=“22sp”
android:textStyle=“bold” />
最后
在此为大家准备了四节优质的Android高级进阶视频:
架构师项目实战——全球首批Android开发者对Android架构的见解
附相关架构及资料
[外链图片转存中…(img-oxXUfXgc-1715732633519)]
往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!