Android TV开发:设置全局焦点框及listview中item的焦点获取

1、设置全局焦点框

创建一个FocusLayout.java文件

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
/**
* Created by LCN_Louis on 2017/9/5.
*/
public classFocusLayoutextendsRelativeLayoutimplementsViewTreeObserver.OnGlobalFocusChangeListener{
private LayoutParamsmFocusLayoutParams;
private View mFocusView;
public FocusLayout(Contextcontext) {
super(context);
init(context);
}
public FocusLayout(Contextcontext,AttributeSet attrs) {
super(context,attrs);
init(context);
}
public FocusLayout(Contextcontext,AttributeSet attrs,int defStyle) {
super(context,attrs,defStyle);
init(context);
}
private void init(Contextcontext) {
this.mFocusLayoutParams= newRelativeLayout.LayoutParams(0,0);
this.mFocusView = new View(context);
this.mFocusView.setBackgroundResource(R.drawable.default_focus);
this.addView(this.mFocusView,this.mFocusLayoutParams);
}
@Override
public voidonGlobalFocusChanged(ViewoldFocus,View newFocus) {
try {
Rect viewRect = new Rect();
newFocus.getGlobalVisibleRect(viewRect);
correctLocation(viewRect);
this.setFocusLocation(
viewRect.left- this.mFocusView.getPaddingLeft(),
viewRect.top- this.mFocusView.getPaddingTop(),
viewRect.right+ this.mFocusView.getPaddingRight(),
viewRect.bottom+ this.mFocusView.getPaddingBottom());
}catch (NullPointerExceptione){
e.printStackTrace();
}
}
/**
* 由于getGlobalVisibleRect获取的位置是相对于全屏的,所以需要减去FocusLayout本身的左与上距离,变成相对于FocusLayout
*@paramrect
*/
private voidcorrectLocation(Rectrect) {
Rect layoutRect = new Rect();
this.getGlobalVisibleRect(layoutRect);
rect.left-=layoutRect.left;
rect.right-=layoutRect.left;
rect.top-=layoutRect.top;
rect.bottom-=layoutRect.top;
}
/**
* 设置焦点view的位置,计算焦点框的大小
*
* @paramleft
*@paramtop
*@paramright
*@parambottom
*/
protected voidsetFocusLocation(intleft,int top,int right,int bottom) {
int width =right-left;
int height = bottom - top;
this.mFocusLayoutParams.width=width;
this.mFocusLayoutParams.height=height;
this.mFocusLayoutParams.leftMargin=left;
this.mFocusLayoutParams.topMargin=top;
this.mFocusView.layout(left,top,right, bottom);
}
}

default_focus

在Activity中添加 

FocusLayout mFocusLayout;//焦点层 实现OnGlobalFocusChangeListener接口

@Override
public void setContentView(int layoutResID) {
    super.setContentView(layoutResID);
    mFocusLayout = new FocusLayout(this);
    bindListener();//绑定焦点变化事件
    addContentView(mFocusLayout,
            new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT));//添加焦点层
}

private void bindListener() {
    //获取根元素
    View mContainerView = this.getWindow().getDecorView();//.findViewById(android.R.id.content);
    //得到整个view树的viewTreeObserver
    ViewTreeObserver viewTreeObserver = mContainerView.getViewTreeObserver();
    //给观察者设置焦点变化监听
    viewTreeObserver.addOnGlobalFocusChangeListener(mFocusLayout);
}



2、listview中item的焦点获取

activity中
mPoseLV = (ListView) findViewById(R.id.lv_pose_view);
mPoseLV.setItemsCanFocus(true);  //关键代码
mPoseLV.setFocusable(false);	//将listview设置为不可获取焦点,不然listview会最外层会有焦点框
mPoseList = new ArrayList<LectureQuestion>();
mPoseAdapter = new MyListViewAdapter<LectureQuestion>(this, mPoseList, mHandler);
mPoseLV.setAdapter(mPoseAdapter);
mPoseLV.setOnItemClickListener(new AdapterView.OnItemClickListener() 

进入MyListViewAdapter

public class MyListViewAdapter<T> extends BaseAdapter

getview中

给item的布局设置为可获取焦点,同时设置点击事件用来代替原本listview的点击事件(因为原本的listview被设置为了不可获取焦点所以下面这个点击item

mPoseLV.setOnItemClickListener
点击事件就没用了)

LinearLayout mquestion_layout = ViewHolder.get(convertView, R.id.question_layout);
mquestion_layout.setFocusable(true);
mquestion_layout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Message msg = new Message();
        msg.what = SHOWPOSE;
        msg.arg1 = position;
        mHandler.sendMessage(msg);
    }
});

传Message到Activity中进行handler处理

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
case SHOWPOSE:
    chooseItemPosition = msg.arg1;
  /*
***
***
***
***
*/
    break;
 }
};

焦点item的水平/垂直滚动RecyclerView-LayoutManager。仿Android豆瓣书影音“推荐“频道列表布局效果截图: GIF:  可自己监听滚动编写效果,如修改成仿MacOS文件浏览: 依赖api 'com.ccy:FocusLayoutManager:1.0.1' // (or implementation)使用focusLayoutManager =                 new FocusLayoutManager.Builder()                         .layerPadding(dp2px(this, 14))                         .normalViewGap(dp2px(this, 14))                         .focusOrientation(FocusLayoutManager.FOCUS_LEFT)                         .isAutoSelect(true)                         .maxLayerCount(3)                         .setOnFocusChangeListener(new FocusLayoutManager.OnFocusChangeListener() {                             @Override                             public void onFocusChanged(int focusdPosition, int lastFocusdPosition) {                                                              }                         })                         .build(); recyclerView.setLayoutManager(focusLayoutManager);各属性意义见图: 注意:因为item在不同区域随着滑动会有不同的缩放,所以实际layerPadding、normalViewGap会被缩放计算。调整动画效果:new FocusLayoutManager.Builder()                         ......                         .setSimpleTrasitionListener(new FocusLayoutManager.SimpleTrasitionListener() {                              @Override                             public float getLayerViewMaxAlpha(int maxLayerCount) {                                 return super.getLayerViewMaxAlpha(maxLayerCount);                             }                             @Override                             public float getLayerViewMinAlpha(int maxLayerCount) {                                 return super.getLayerViewMinAlpha(maxLayerCount);                             }                             @Override                             public float getLayerChangeRangePercent() {                                 return super.getLayerChangeRangePercent();                             }                             //and more                                                          //更多可重写方法和释义见接口声明                         })                         .build();自定义动画/滚动监听:如果你想在滑动时不仅仅改变item的大小、透明度,你有更多的想法,可以监听TrasitionListener,该监听暴露了很多关键布局数据,......             .setSimpleTrasitionListener(null) //如果默认动画不想要,移除之。or use removeTrasitionlistener(XXX)              .addTrasitionListener(new FocusLayoutManager.TrasitionListener() {                             @Override                             public void handleLayerView(FocusLayoutManager focusLayoutManager,                                                         View view, int viewLayer,                                                         int maxLayerCount, int position,                                                         float fraction, float offset) {                                                              }                             @Override                             public void handleFocusingView(FocusLayoutManager focusLayoutManager,                                                            View view, int position,                                                            float fraction, float offset) {                             }                             @Override                             public void handleNormalView(FocusLayoutManager focusLayoutManager, View view, int position, float fraction, float offset) {                             }                         })各参数意义见接口注释。 实际上SimpleTrasitionListener内部就会被转为TrasitionListener。可参考转换类是怎么做的:TrasitionListenerConvert源码解析https://blog.csdn.net/ccy0122/article/details/90515386
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值