本文记录作者自己在开发Android TV应用的时候遇到的问题并记录之,供后续查漏补缺。
1. Android 原生控件的 Focusable 的默认值的问题?
一般系统的自带控件focusable 的值,有 button及其子类RadioButton、CheckedBox , EditText,还有ListView,Recycleiew 等列表类控件为true, 其余的都为false。
View[] viewFocusable = new View[]{mButton, mLinearLayout, mImageView, mImageButton, mView, mTextView, mEditText, frameLayout ,relativeLayout};
for (View v: viewFocusable) {
Log.d(TAG, v.toString() + "focusable 的值为:" + v.isFocusable());
}
打印的值为:
android.support.v7.widget.AppCompatButton{4221f9d8 VFED..C. ......I. 0,0-0,0 #7f090043 app:id/btn}focusable 的值为:true
android.widget.LinearLayout{4227c2d8 VFE..... ......I. 0,0-0,0 #7f0900db app:id/llayout}focusable 的值为:true
android.support.v7.widget.AppCompatImageView{421f5280 V.ED.... ......I. 0,0-0,0 #7f0900aa app:id/imageView}focusable 的值为:false
android.support.v7.widget.AppCompatImageButton{41fe4670 VFED..C. ......I. 0,0-0,0 #7f0900a9 app:id/imageButton}focusable 的值为:true
android.view.View{421d7400 V.ED.... ......I. 0,0-0,0 #7f090150 app:id/view}focusable 的值为:false
android.support.v7.widget.AppCompatTextView{4221b9b0 V.ED.... ......ID 0,0-0,0 #7f09014a app:id/tv}focusable 的值为:false
android.support.v7.widget.AppCompatEditText{42222650 VFED..CL ......I. 0,0-0,0 #7f090079 app:id/et}focusable 的值为:true
android.widget.FrameLayout{421e12f0 V.E..... ......I. 0,0-0,0 #7f090084 app:id/frameLayout}focusable 的值为:false
android.widget.RelativeLayout{41fe4f90 V.E..... ......I. 0,0-0,0 #7f09010c app:id/rlLayout}focusable 的值为:false
针对第二个linearLayout 的值为 true, 是因为在xml中 设置focusable = true 导致的。一般的,容器控件的view 其 focusable 都为 false,除非你设置了。
那针对ListView、recycleView这种控件呢, 以及他们的Item 呢?
答案是他们默认是True, 他们和一般容器控件不一样 。以ListView为例,体统源码中有设置:setFocusableInTouchMode(true);
同理recycleView也都一样。而对于item而言,我们需要进行设置
private boolean mItemsCanFocus = false;
/**
* Indicates that the views created by the ListAdapter can contain focusable
* items.
*
* @param itemsCanFocus true if items can get focus, false otherwise
*/
public void setItemsCanFocus(boolean itemsCanFocus) {
mItemsCanFocus = itemsCanFocus;
if (!itemsCanFocus) {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
/**
* @return Whether the views created by the ListAdapter can contain focusable
* items.
*/
public boolean getItemsCanFocus() {
return mItemsCanFocus;
}
上面是ListView中关于item能否聚焦的核心代码,一看就明了。而RecycleView 对于item而言,则需要在
@Override
public void onBindViewHolder(@NonNull final Holder holder, int i) {
//设置item 可以点击
holder.itemView.setFocusable(true);
holder.itemView.setFocusableInTouchMode(true);
}
2. 当用遥控器控制焦点移动时,其会遵循一个什么样的规律呢?
一般来说:系统会自动的把焦点移到距离最近的可触控的控件(focusable为true),所以当我们在一个viewGroup (没有进行特殊设置)包裹了一个可以的点击的Button,这时候他会自动的把焦点聚焦在button上,如果你对ViewGroup 进行设置可聚焦,那么焦点会获取焦点,button就无法聚焦,除非你对viewGroup 进行 onFocusableChangeListener监听,并让button 强制获取焦点
v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus){
Log.d(TAG, "onFocusChange: hasFocus" + v.toString());
// do something
}else {
// do something
Log.d(TAG, "onFocusChange: lostFocus" + v.toString());
}
}
});