Android TV 控件获取焦点特效

最近开始接触TV端开发,初转入TV端,有好多不适应。尤其是对焦点的处理,上篇文章对leanback的使用做了简单的介绍,并对Item获取焦点后的高亮显示进行了处理。但是,如果按照同样的方法在非列表页实现时,效果并不理想,并会出现难以控制等问题。于是,开始寻找新的实现方式。在网上找了好多实现方式,均不是特别理想。最终找到了一篇比较满意的文章,自己在此基础上进行了优化改进。Demo的截图如下:



下面就详细介绍一下实现流程吧。

(1)自定义View,实现获取焦点时放大,失去焦点时缩小,详细代码如下:

package cn.chinaiptv.newaikan.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.RelativeLayout;

import cn.chinaiptv.newaikan.R;

public class FocusRelativeLayout extends RelativeLayout {

    private Rect mBound;
    private Drawable mDrawable;
    private Rect mRect;

    private Animation scaleSmallAnimation;
    private Animation scaleBigAnimation;

    public FocusRelativeLayout(Context context) {
        super(context);
        init();
    }

    public FocusRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public FocusRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    protected void init() {
        setWillNotDraw(false);
        mRect = new Rect();
        mBound = new Rect();
        //获取焦点后,外侧的阴影图片
        mDrawable = getResources().getDrawable(R.drawable.poster_shadow_4);
        setChildrenDrawingOrderEnabled(true);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (hasFocus()) {
            super.getDrawingRect(mRect);
            mBound.set(-5+mRect.left, -5+mRect.top, 5+mRect.right, 5+mRect.bottom);
            mDrawable.setBounds(mBound);
            canvas.save();
            mDrawable.draw(canvas);
            canvas.restore();
        }
        super.onDraw(canvas);
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        if (gainFocus) {
            bringToFront();
            getRootView().requestLayout();
            getRootView().invalidate();
            zoomOut();
        } else {
            zoomIn();
        }
    }

    /**
     * 缩小动画
     */
    private void zoomIn() {
        if (scaleSmallAnimation == null) {
            scaleSmallAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_small);
        }
        startAnimation(scaleSmallAnimation);
    }

    /**
     * 放倒动画
     */
    private void zoomOut() {
        if (scaleBigAnimation == null) {
            scaleBigAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_big);
        }
        startAnimation(scaleBigAnimation);
    }

}

(2)定义两个放大和缩小的动画文件

放大的动画文件:anim_scale_big.xml




    


缩小的动画文件:anim_scale_small.xml




    


(3)准备工作就结束下,下面开始些布局文件。由于本例子中的图片布局基本类似,所以就单独给出一个item文件(例子中使用了圆角图片,在此不再贴出代码):




    

    


(4)引用定义好的子布局:




    

    

    

    

    

    

    

    

    

    




最后,在JAVA代码处理滑动到最左侧,最右侧,最下方时。进行模块切换,具体代码如下:
package cn.chinaiptv.newaikan.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;

import cn.chinaiptv.newaikan.R;
import cn.chinaiptv.newaikan.view.FocusRelativeLayout;


/**
 * Created by ddklsy163com on 16/12/19.
 */

public class FragmentTwo extends Fragment implements ViewTreeObserver.OnGlobalFocusChangeListener {
    private View view;

    private FocusRelativeLayout channel_0;
    private FocusRelativeLayout channel_1;
    private FocusRelativeLayout channel_2;
    private FocusRelativeLayout channel_3;
    private FocusRelativeLayout channel_4;
    private FocusRelativeLayout channel_5;
    private FocusRelativeLayout channel_6;
    private FocusRelativeLayout channel_7;
    private FocusRelativeLayout channel_8;
    private FocusRelativeLayout channel_9;
    private RelativeLayout fragment_two;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null) {
                parent.removeView(view);
            }
            return view;
        }
        view = inflater.inflate(R.layout.fragment_two, null);
        initView(view);
        fragment_two.getViewTreeObserver().addOnGlobalFocusChangeListener(this);
        return view;
    }

    private void initView(View view) {
        fragment_two = (RelativeLayout) view.findViewById(R.id.fragment_two);
        channel_0 = (FocusRelativeLayout) view.findViewById(R.id.channel_0);
        channel_1 = (FocusRelativeLayout) view.findViewById(R.id.channel_1);
        channel_2 = (FocusRelativeLayout) view.findViewById(R.id.channel_2);
        channel_3 = (FocusRelativeLayout) view.findViewById(R.id.channel_3);
        channel_4 = (FocusRelativeLayout) view.findViewById(R.id.channel_4);
        channel_5 = (FocusRelativeLayout) view.findViewById(R.id.channel_5);
        channel_6 = (FocusRelativeLayout) view.findViewById(R.id.channel_6);
        channel_7 = (FocusRelativeLayout) view.findViewById(R.id.channel_7);
        channel_8 = (FocusRelativeLayout) view.findViewById(R.id.channel_8);

        channel_9 = (FocusRelativeLayout) view.findViewById(R.id.channel_9);
    }

    @Override
    public void onGlobalFocusChanged(View oldFocus, View newFocus) {
        switch (newFocus.getId()) {
            case R.id.channel_0:
            case R.id.channel_1:
                channel_0.setNextFocusLeftId(R.id.tv_one);
                channel_1.setNextFocusLeftId(R.id.tv_one);
                channel_1.setNextFocusDownId(R.id.tv_two);
            case R.id.channel_8:
            case R.id.channel_9:
                channel_8.setNextFocusRightId(R.id.tv_three);
                channel_9.setNextFocusRightId(R.id.tv_three);
                channel_9.setNextFocusDownId(R.id.tv_two);
                break;
            case R.id.channel_2:
            case R.id.channel_3:
            case R.id.channel_4:
            case R.id.channel_5:
            case R.id.channel_6:
            case R.id.channel_7:
                channel_3.setNextFocusDownId(R.id.tv_two);
                channel_5.setNextFocusDownId(R.id.tv_two);
                channel_7.setNextFocusDownId(R.id.tv_two);
                break;
        }
    }
}

到此,就完美实现了获取焦点的高亮显示。

你可能感兴趣的:(android,TV端开发)