导入对应布局生成的模板类,举例:
import kotlinx.android.synthetic.main.activity_newtimelapseplus.*
import kotlinx.android.synthetic.main.fragment_newtimelapsepluspath.*
import kotlinx.android.synthetic.main.fragment_newtimelapseplussetting.*
import kotlinx.android.synthetic.main.layout_newtimelapseplus_setting_item.view.iv_icon as item1_iv_icon
import kotlinx.android.synthetic.main.layout_newtimelapseplus_setting_item3.view.*
代码中直接引用布局中定义的id来使用对应控件:
xml:
R.layout.activity_newtimelapseplus 中有
code:
导入import kotlinx.android.synthetic.main.activity_newtimelapseplus.* (对应R.layout.activity_newtimelapseplus自动生成)
其中包含R.layout.activity_newtimelapseplus中定义的对应控件id的所有控件
vg_pager (vg_pager是对应id自动生成的变量,声明为android.support.v4.view.ViewPager vg_pager)
后续的代码直接使用vg_pager这个变量即可。省略了定义控件变量、给控件变量绑定id和赋值的代码。
vg_pager等控件变量如果使用不当,会出现报空指针的情况,这是因为走的流程不对,导致vg_pager等变量没有被初始化
vg_pager最标准的使用格式,应该是:
rootView.vg_pager
其中rootView是包含vg_pager控件的父容器ViewGroup。
在Activity、Fragment、自定义View中使用时,系统会默认vg_pager等变量的前缀是当前上下文所使用的ViewGroup,
比如在Activity中使用时,默认省略了rootView对vg_pager的调用,vg_pager默认从当前Activity的contentView中获取
在Fragment中使用时,默认从Fragment在onCreateView中返回的View中获取,即Fragment调用getView()所返回的那个View,即Fragment的rootView
所以在Activity、Fragment、继承自ViewGroup的自定义View中使用对应id的控件变量时,不需要加前缀,不需要rootView.vg_pager的形式,直接使用vg_pager的形式就可以了
(在Activity、Fragment中使用时因为隐藏了一些细节,所以使用起来会简单一些。但如果不知道这个过程可能会报错,
由这个过程可知vg_pager是有隐藏的初始化的代码的,即从Activity、Fragment中获取rootView进行findById初始化,如果在Activity没有setContentView、Fragment没有onCreateView之前使用了vg_pager等控件变量,那肯定是会报空指针的)
在非Activity、Fragment中使用时,默认vg_pager等变量从当前上下文中获取rootView进行初始化,比如在自定义View中使用时,默认this.vg_pager这种形式,如果this不是ViewGroup类型就会报错,无法使用。
一般,如果在非Activity、Fragment中使用,以这种形式:rootView.vg_pager,显式的指明vg_pager的父容器,这样就正常了。(kotlin android extensions插件,会让所有为ViewGroup类型的变量都可以调用kotlinx.android.synthetic.main中生成的控件变量)
到时系统会默认从rootView中findById给vg_pager赋值初始化
(注意,比如在Fragment中使用时是导入import kotlinx.android.synthetic.main.fragment_newtimelapsepluspath.*
如果显式指明控件变量的父容器的话,要换成:import kotlinx.android.synthetic.main.fragment_newtimelapsepluspath.view.*)
可以看到kotlin android extensions是通过使用控件id的名称来引用控件,所以在这里id命名需要注意
我发现一个问题,
import kotlinx.android.synthetic.main.layout_newtimelapseplus_setting_item.view.* 中定义了id:tv_title
import kotlinx.android.synthetic.main.layout_newtimelapseplus_setting_item3.view.* 中也定义了id:tv_title
那么在代码中引用时就会出现冲突,使用tv_title变量会报错,因为它不知道是使用layout_newtimelapseplus_setting_item还是layout_newtimelapseplus_setting_item3中的tv_title
实际上不管用哪个tv_title,只要id正确类型正确都是可以的,因为这个id并不代表真正的变量
(前面说vg_pager对应的是 android.support.v4.view.ViewPager vg_pager,这是为了方便解释,实际上底层隐藏有语法糖,代码比这个形式复杂些,要解释的话,更类似于"rootView.findViewById(R.id.vg_pager)
"这种形式)
虽然使用任意的都可以,但有冲突的话会导致都用不了,这个问题Kotlin暂时没有找到比较好的解决方法,这个也确实不太好解决,
我们自己findById没有重名问题,因为返回的都是View类型
而自动生成的id控件是附带具体类型的,在kotlin android extensions中而多个同名id控件是无法区分类型的(比如layout1中有TextView命名id为myView,layout2中有ImageView命名id也为myView,代码如果不区分布局导入id就不知道myView是哪个类型),
所以导包重名的问题确实存在而且暂时没办法好好解决
如果layout1中有TextView命名id为myView,layout2中也有TextView命名id也为myView,这个时候在代码中不管使用哪个都没关系的,因为恰巧都是同名、同类型
对于同名同类型的冲突,不要同时导入两个layout中的id,导其中一个就行,以免同时导入了同名的变量,或者不使用*导入,每次使用时都单独导入对应的id也可以,如kotlinx.android.synthetic.main.layout_newtimelapseplus_setting_item.view.tv_title的形式
但对于同名不同类型的情况,目前我只能想到用重命名的方式:
导入layout1.view.myView
导入layout2.view.myView as myTextView
在使用多布局列表时可能会遇到这种困扰,这个时候可以使用时不使用*导入,或单独导入,或有同名不同类的冲突就用as重命名一下