
纸上得来终觉浅,绝知此事要躬行。
动手实践是学习的最好的方式,对于自定义View来说,听和看只能是过一遍流程,能掌握个30%、40%就不错了,而且很快就会遗忘,想变成自己的东西必须动手来写几遍,细细体会其中的细节和系统API的奥秘、真谛。
进入主题,今天来手写一个瀑布流组件FlowLayout,温习下自定义view的流程和关键点,先来张效果图
FlowLayout实现关键步骤: 1、创建一个view继承自ViewGroup
class ZSFlowLayout : ViewGroup {
constructor(context: Context) : super(context) {}
constructor(context: Context, attr: AttributeSet) : super(context, attr) {}
constructor (context: Context, attr: AttributeSet, defZStyle: Int) : super(
context,
attr,
defZStyle
) {
}
}
这里注意两个参数的构造函数是必须的构造函数,系统会通过反射来调用此构造方法完成view的创建,具体调用位置在LayoutInflater 的 createView方法中,如下(基于android-31):
省略了若干不相关代码,并写了重要的注释信息,请留意
public final View createView(@NonNull Context viewContext, @NonNull String name,
@Nullable String prefix, @Nullable AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Objects.requireNonNull(viewContext);
Objects.requireNonNull(name);
//从缓存中取对应的构造函数
Constructor extends View> constructor = sConstructorMap.get(name);
Class extends View> clazz = null;
try {
if (constructor == null) {
// 通过反射创建class对象
clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
mContext.getClassLoader()).asSubclass(View.class);
//创建构造函数 这里的mConstructorSignature 长这个样子
//static final Class>[] mConstructorSignature = new Class[] {
// Context.class, AttributeSet.class};
//看到了没 就是我们第二个构造方法
constructor = clazz.getConstructor(mConstructorSignature);
constructor.setAccessible(true);
//缓存构造方法
sConstructorMap.put(name, constructor);
} else {
...
}
try {
//执行构造函数 创建出view
final View view = constructor.newInstance(args);
...
return view;
} finally {
mConstructorArgs[0] = lastContext;
}
} catch (Exception e) {
...
} finally {
...
}
}
2、重写并实现onMeasure方法
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
}
这里要重点解释下 widthMeasureSpec 和 heightMeasureSpec是怎么来的
3、重写并实现onLayout方法欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)