首页 > 开发 > Android > 正文

Android TV 重写GridView,实现焦点放大效果

2016-05-18 19:21:38  来源:慕课网

  
关于缩放,使用了view.setScaleX/Y 方法,api11以上即可。
重写dispatchDraw(),绘制选中项的焦点效果。(注意带阴影的焦点图需要微调偏移量)
要将选中项绘制显示在顶层,所以要改变GridView的子View绘制顺序;
所以要重写bringChildToFront、getChildDrawingOrder,同时要打开setChildrenDrawingOrderEnabled(true)。
在缩放代码中添加了监听器,用于调用端,设置回调。
  注意: 如果GridView的最后一行的个数少于列数,在较少的列上向下,会报异常。 还有就是当快速切换时,可能会看到默认的listSelector,可以将其设置为透明的。

package com.stone.tvapplication.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.stone.tvapplication.R;
import com.stone.tvapplication.util.AdaptionAlgo;

/**
 * 重写dispatchDraw,在选中项上绘制一个focus-drawable
 *
 * author : stone
 * email  : aa86799@163.com
 * time   : 16/5/11 10 20
 */
public class TvFocusGridView extends GridView {

    private Drawable mFocusBackDrawable;
    private Rect mFocusBackRect;
    private int mSelectedPosition;
    private View mSelectedView;
    private float mScaleX;
    private float mScaleY;
    private onItemFocusSelectedListener mOnItemFocusSelectedListener;

    public TvFocusGridView(Context context) {
        this(context, null);
    }

    public TvFocusGridView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TvFocusGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        setClipChildren(false);
        setClipToPadding(false);
        setChildrenDrawingOrderEnabled(true);//设置绘制顺序可重定义,需要重写getChildDrawingOrder来变化绘制顺序

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TvFocusGridView);
        mFocusBackDrawable = array.getDrawable(R.styleable.TvFocusGridView_focus_background);

        array.recycle();

        mFocusBackRect = new Rect();
        mFocusBackDrawable.getPadding(mFocusBackRect); //Drawable中实际填充图像的Rect
//        System.out.println("mFocusBackRect-->" + mFocusBackRect);

    }

    public interface onItemFocusSelectedListener {
        void onFocused(View child, int position);
        void unfocused(View child, int position);
    }

    public void setOnItemFocusSelectedListener(onItemFocusSelectedListener onItemFocusSelectedListener) {
        this.mOnItemFocusSelectedListener = onItemFocusSelectedListener;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (mFocusBackDrawable == null) {
            return;
        }
        drawSelector(canvas);

    }

    private void drawSelector(Canvas canvas) {
        View view = getSelectedView();
        if (view == null) return;

        bringChildToFront(view);

        if (isFocused()) {
            scaleSelectedView(view);

            Rect gvVisibleRect = new Rect();
            this.getGlobalVisibleRect(gvVisibleRect); //GridView可见区 在屏幕中的绝对坐标 rect
            Rect selectedViewRect = new Rect();
            if (mSelectedView instanceof ViewGroup) {
                mSelectedView.getGlobalVisibleRect(selectedViewRect); //选中View可见区 在屏幕中的绝对坐标 rect
                selectedViewRect.offset(-gvVisibleRect.left, - gvVisibleRect.top); //偏移
                selectedViewRect.left -= mFocusBackRect.left +  40;//+阴影偏移
                selectedViewRect.top -= mFocusBackRect.top + 20;
                selectedViewRect.right += mFocusBackRect.right + 40;
                selectedViewRect.bottom += mFocusBackRect.bottom + 20;

                mFocusBackDrawable.setBounds(selectedViewRect);
                mFocusBackDrawable.draw(canvas);
            }

        }
    }

    /**
     * 使子view位置在上层
     * @param child
     */
    @Override
    public void bringChildToFront(View child) { //重写,不调用父类方法;获取child的实际position
//        super.bringChildToFront(child);
        mSelectedPosition = indexOfChild(child);
        invalidate();
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {//交换 选中项与最后一项 绘制的顺序
        if (mSelectedPosition != AbsListView.INVALID_POSITION) {
            if (i == mSelectedPosition) {
                return childCount - 1;
            }
            if (i == childCount - 1) {
                return mSelectedPosition;
            }
        }

        return super.getChildDrawingOrder(childCount, i);
    }

    private void scaleSelectedView(View view) {//缩放
        unScalePreView();

        mSelectedView = view;
        mSelectedView.setScaleX(mScaleX); //api11
        mSelectedView.setScaleY(mScaleY);

        if (mOnItemFocusSelectedListener != null) {
            mOnItemFocusSelectedListener.onFocused(mSelectedView, indexOfChild(mSelectedView));
        }
    }

    private void unScalePreView() {//还原
        if (mSelectedView != null) {
            mSelectedView.setScaleX(1);
            mSelectedView.setScaleY(1);

            if (mOnItemFocusSelectedListener != null) {
                mOnItemFocusSelectedListener.unfocused(mSelectedView, indexOfChild(mSelectedView));
            }

            mSelectedView = null;

        }
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {//整个GridView焦点状态
        if (!gainFocus) {
            unScalePreView();
            requestLayout();
        }
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
    }

    public void setScale(float scaleX, float scaleY) {
        this.mScaleX = scaleX;
        this.mScaleY = scaleY;

    }
}

  

调用端设置与监听:

mGridView.setAdapter(mAdapter);
mGridView.setScale(1.2f, 1.2f);
mGridView.setHorizontalSpacing(AdaptionAlgo.scaleX(30));
mGridView.setVerticalSpacing(AdaptionAlgo.scaleY(30));
mGridView.setPadding(60, 40, 60, 40);

mGridView.setOnItemFocusSelectedListener(new TvFocusGridView.onItemFocusSelectedListener() {
    @Override
    public void onFocused(View child, int position) {
        TextView tv = getViewById(child, R.id.tv_text);
        tv.setTextColor(Color.RED);
    }

    @Override
    public void unfocused(View child, int position) {
        TextView tv = getViewById(child, R.id.tv_text);
        tv.setTextColor(Color.MAGENTA);
    }
});

  核心代码出自:http://blog.csdn.net/coderinchina/article/details/51344970