需求是这样的:
- 需要自定义一个控件来检测EditEext的状态
- 在xml中自己写属性,传入EditText的Id
- 尽量减少在Activity中的代码量,降低耦合度
难点
- 在这之前,不知道属性中可以直接传入id
- 拿到id后,无可以findViewById的实例
- 获取到的EditText和Activity中的EditText不是同一个实例
首先,我们自定义一个属性,暂且称之为bind_view
在xml文件中引用,并将我们所需要绑定的EditText的Id传入
9XTNK0R8HF$6EQ0)VNV{7QP.png在我们所写的自定义view的构造函数中,获取TypedArray
final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TextBindView);
在debug模式下看到,我们传入的id在TypedArray中
此时,需求就变得简单了,在尝试了getInt,getType未果之后,我们使用了getResourceId获取到了真正的绑定的EditText的Id
int resId = ta.getResourceId(R.styleable.TextBindView_bind_view, 0);
突然发现,我们所绑定的View不是我们自定义View的子View,而View的findViewById是向下遍历,此时机智的我想到了再定义一个属性
J(PAANH1T0913OHPZB%ZNAK.png通过这个属性,传入layout,通过layout来findViewById
app:parent_view="@layout/activity_main"
然而,此时发现,在构造函数中是无法View.inflate的,真是个悲伤的故事,通过上网查阅资料,知道这是由于生命周期的缘故,想要inflate,必须在onAttachedToWindow方法中进行,于是我将函数迁移至onAttachedToWindow方法中。
在这里,我们成功的获得了我们所绑定的EditText,并且获取到了text,此时,我想在这里给EditText设置一个textWatcher,事情就大功告成了,结果并不尽如人意。
给Edittext设置textWatcher后,发现改变Edittext的内容没有什么卵用。让我一度怀疑人生了,再使用settext同样没有什么用,仔细思考之后,认为:
通过View.inflate来获取到的ViewRoot,再进行findViewById所得到的View,和我们Activity通过setContentView绘制出的View并不是同一个View。这段话可能有点绕,总的来说就是一句话,setContentView和inflater加载出来的是两个不同的实例。
此时,事情又回到刚开始了,难道真的要在activity给我们所自定义的View添加一个要监听的EditText吗?
秉着没有代码做不到的事情,我上网查阅资料得出:
-
同一个activity 通过findViewById来获取到的View 永远都是同一个View
-
第二点也是最重要的一点,View中的context其实是Activity向上转型得到的,我们只需要将其向下转型即可得到当前界面的activity
最终,我们直接根据得到的resId,使用activity.findViewById来获取我们绑定的Edittext。
CB7_SCQ(_0DY}M(%TENE%~X.png此时,我们终于达成了本次自定义View的最终需求。成功在xml中传入绑定的Id来监听edittext。