打造一个带有模拟焦点的影视剧集选集组件

来源:互联网 发布:vue.js获取json数据 编辑:程序博客网 时间:2024/04/18 23:04

过程分析

安卓机顶盒开发中,很多时候都需要我们能够有自定义View的能力。而且通常需要处理按键相关的逻辑,其实就是和焦点相关的逻辑。我这里说的焦点并非之前的博文中提到的焦点。前面说到的焦点是一个被标记的View。我这里说的是视觉上的焦点,就是你能够看到的被标记的位置。通常我们处理焦点问题,可以采用安卓提供的焦点相关的api。当然我们也可以自己模拟实现焦点。本文将带你实现一个较为简单的模拟焦点的自定义View。在720p分辨率的安卓盒子上运行效果如下:

image

代码实现

  • 这里贴一下主要的类:
package com.ajay.tvdevelopdemo.widget;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.KeyEvent;import android.view.View;import java.util.List;/** * 该组件模拟view内部视觉焦点移动 * * @author AjayNiu * @since 2016-11-14 */public class EpisodeChooseLayout extends View {    public static final String TAG = "EpisodeChooseLayout";    public static final boolean DEBUG = false;    public static final int TEXT_SIZE = 20;    public static final String FOCUS_COLOR = "#005DBE";    public static final String UNFOCUS_COLOR = "#B3B5BB";    public static final String UNFOCUS_HASSEEN_COLOR = "#898989";    public static final String FOCUS_TEXT_COLOR = "#FFFFFF";    public static final String UNFOCUS_TEXT_COLOR = "#000000";    private static final int SCROLL_TYPE_EDGE = 0;    private static final int SCROLL_TYPE_MIDDLE = 1;    private int mScrollType = SCROLL_TYPE_EDGE;    private int mTextSize = TEXT_SIZE;    private int mFocusItemColor;    private int mUnFocusItemColor;    private int mUnFocusHasSeenItemColor;    private int mFocusTextColor;    private int mUnFocusTextColor;    // 模拟焦点距控件边缘的距离    private int focusStayExtra;    // 可见轴线起始绝对坐标    private int mVisibleStartX;    // 可见轴线结束绝对坐标    private int mVisibleEndX;    // 上次滚动位置    private int lastScrollPosition;    // 实际绘制的条目数据集合    private List<EpisodeChooseItem> mDrawingItems;    private Paint mPaint = new Paint();    private Paint mTextPaint = new Paint();    private Rect focusUpRect = new Rect();    private Rect unFocusUpRect = new Rect();    private Rect mVisibleRect = new Rect();    // item之间的水平间隔    private static final int GAP = 1;    // 焦点位置    private int mFocusPosition;    // 是否得到焦点    private boolean isGainFocus;    // 已观看的最大位置    private int mHasSeenMaxPosition;    // 文本区域    private Rect mTextRect = new Rect();    public EpisodeChooseLayout(Context context) {        super(context);        init();    }    public EpisodeChooseLayout(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    private void init() {        setFocusable(true);        mPaint.setAntiAlias(true);        mTextPaint.setAntiAlias(true);        mFocusItemColor = Color.parseColor(FOCUS_COLOR);        mUnFocusItemColor = Color.parseColor(UNFOCUS_COLOR);        mUnFocusHasSeenItemColor = Color.parseColor(UNFOCUS_HASSEEN_COLOR);        mFocusTextColor = Color.parseColor(FOCUS_TEXT_COLOR);        mUnFocusTextColor = Color.parseColor(UNFOCUS_TEXT_COLOR);    }    public void initItems(List<EpisodeChooseItem> mInitItems) {        if (mInitItems.size() <= 0) {            return;        }        int left = 0;        for (int i = 0; i < mInitItems.size(); i++) {            EpisodeChooseItem item = mInitItems.get(i);            item.position = mInitItems.indexOf(item);            item.rect.left = left;            item.rect.top = 0;            item.rect.right = item.rect.left + item.getWidth();            item.rect.bottom = item.getHeight();            left += item.getWidth();        }        this.mDrawingItems = mInitItems;    }    @Override    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);        if (gainFocus) {            isGainFocus = true;            invalidate();        } else {            isGainFocus = false;            invalidate();        }    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        if (changed) {            mVisibleStartX = focusStayExtra;            mVisibleEndX = getMeasuredWidth() - focusStayExtra;            mVisibleRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());        }    }    public void updateHasSeenMaxPosition(int mHasSeenMaxPosition) {        this.mHasSeenMaxPosition = mHasSeenMaxPosition;        invalidate();    }    public void setFocusPosition(int mFocusPosition) {        this.mFocusPosition = mFocusPosition;        invalidate();    }    public void setFocusStayExtra(int focusStayExtra) {        this.focusStayExtra = focusStayExtra;        invalidate();    }    private void setScrollType(int type) {        mScrollType = type;    }    public void setTextSize(int mTextSize) {        this.mTextSize = mTextSize;    }    public void setmFocusItemColor(int mFocusItemColor) {        this.mFocusItemColor = mFocusItemColor;    }    public void setmUnFocusItemColor(int mUnFocusItemColor) {        this.mUnFocusItemColor = mUnFocusItemColor;    }    public void setmUnFocusHasSeenItemColor(int mUnFocusHasSeenItemColor) {        this.mUnFocusHasSeenItemColor = mUnFocusHasSeenItemColor;    }    public void setmFocusTextColor(int mFocusTextColor) {        this.mFocusTextColor = mFocusTextColor;    }    public void setmUnFocusTextColor(int mUnFocusTextColor) {        this.mUnFocusTextColor = mUnFocusTextColor;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mTextPaint.setTextSize(mTextSize);        canvas.save();        canvas.clipRect(mVisibleRect);        int translatePosition = 0;        if (mScrollType == SCROLL_TYPE_EDGE) {            translatePosition = adjustPositionOnScreen(mFocusPosition);        } else if (mScrollType == SCROLL_TYPE_MIDDLE) {            translatePosition = adjustPositionMiddle(mFocusPosition);        }        canvas.translate(translatePosition, 0);        for (int i = 0; i < mDrawingItems.size(); i++) {            if (i == mFocusPosition) {                Rect rect = mDrawingItems.get(i).rect;                // draw focus up rect                if (isGainFocus) {                    mPaint.setColor(mFocusItemColor);                } else {                    if (i <= mHasSeenMaxPosition) {                        mPaint.setColor(mUnFocusHasSeenItemColor);                    } else {                        mPaint.setColor(mUnFocusItemColor);                    }                }                focusUpRect.set(rect.left, rect.top, rect.right - GAP, rect.bottom);                canvas.drawRect(focusUpRect, mPaint);                if (isGainFocus) {                    mTextPaint.setColor(mFocusTextColor);                } else {                    mTextPaint.setColor(mUnFocusTextColor);                }                // draw message                String text = mDrawingItems.get(i).getMessage();                mTextPaint.getTextBounds(text, 0, text.length(), mTextRect);                int x = mDrawingItems.get(i).rect.left + mDrawingItems.get(i).getWidth() / 2 - mTextRect.width() / 2;                int y = mDrawingItems.get(i).rect.top + mDrawingItems.get(i).getHeight() / 2 + mTextRect.height() / 2;                canvas.drawText(mDrawingItems.get(i).getMessage(), x, y, mTextPaint);            } else {                Rect rect = mDrawingItems.get(i).rect;                // draw focus up rect                if (i <= mHasSeenMaxPosition) {                    mPaint.setColor(mUnFocusHasSeenItemColor);                } else {                    mPaint.setColor(mUnFocusItemColor);                }                unFocusUpRect.set(rect.left, rect.top, rect.right - GAP, rect.bottom);                canvas.drawRect(unFocusUpRect, mPaint);                mTextPaint.setColor(mUnFocusTextColor);                // draw message                String text = mDrawingItems.get(i).getMessage();                mTextPaint.getTextBounds(text, 0, text.length(), mTextRect);                int x = mDrawingItems.get(i).rect.left + mDrawingItems.get(i).getWidth() / 2 - mTextRect.width() / 2;                int y = mDrawingItems.get(i).rect.top + mDrawingItems.get(i).getHeight() / 2 + mTextRect.height() / 2;                canvas.drawText(mDrawingItems.get(i).getMessage(), x, y, mTextPaint);            }        }        canvas.restore();    }    private int adjustPositionMiddle(int focusPosition) {        if (focusPosition >= 0 && focusPosition < mDrawingItems.size()) {            int left = mDrawingItems.get(focusPosition).rect.left;            int width = mDrawingItems.get(focusPosition).getWidth();            int centerX = left + width / 2;            int lastPositionRight = mDrawingItems.get(mDrawingItems.size() - 1).rect.right;            if (lastPositionRight > getMeasuredWidth()) {                if (centerX > getMeasuredWidth() / 2 && centerX < (lastPositionRight - getMeasuredWidth() / 2)) {                    return getMeasuredWidth() / 2 - centerX;                } else if (centerX > (lastPositionRight - getMeasuredWidth() / 2)) {                    return getMeasuredWidth() - lastPositionRight;                }            }        }        return 0;    }    private int adjustPositionOnScreen(int focusPosition) {        if (focusPosition >= 0 && focusPosition < mDrawingItems.size()) {            int focusLeft = mDrawingItems.get(focusPosition).rect.left;            int focusRight = mDrawingItems.get(focusPosition).rect.right;            debugLog("adjustPositionOnScreen focusLeft : " + focusLeft + " mVisibleStartX : " + mVisibleStartX);            debugLog("adjustPositionOnScreen focusRight : " + focusRight + " mVisibleEndX : " + mVisibleEndX);            debugLog("adjustPositionOnScreen extra : " + (mVisibleEndX - mVisibleStartX));            if (focusLeft < mVisibleStartX) {                mVisibleStartX = focusLeft;                mVisibleEndX = focusLeft + getMeasuredWidth() - focusStayExtra * 2;                if (mFocusPosition == 0) {                    lastScrollPosition = -mVisibleStartX;                } else {                    lastScrollPosition = -(mVisibleStartX - focusStayExtra);                }                return lastScrollPosition;            } else if (focusRight > mVisibleEndX) {                mVisibleEndX = focusRight;                mVisibleStartX = focusRight - (getMeasuredWidth() - focusStayExtra * 2);                if (mFocusPosition == mDrawingItems.size() - 1) {                    lastScrollPosition = -(mVisibleStartX - focusStayExtra * 2);                } else {                    lastScrollPosition = -(mVisibleStartX - focusStayExtra);                }                return lastScrollPosition;            } else {                return lastScrollPosition;            }        }        return 0;    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {            if (mFocusPosition > 0) {                mFocusPosition--;                invalidate();                return true;            }        } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {            if (mFocusPosition < mDrawingItems.size() - 1) {                mFocusPosition++;                invalidate();                return true;            }        } else if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {            if (onLayoutClickListener != null) {                onLayoutClickListener.onLayoutClick(mFocusPosition);            }        }        return super.onKeyDown(keyCode, event);    }    public interface OnLayoutClickListener {        void onLayoutClick(int position);    }    OnLayoutClickListener onLayoutClickListener;    public void setOnLayoutClickListener(OnLayoutClickListener onLayoutClickListener) {        this.onLayoutClickListener = onLayoutClickListener;    }    private void debugLog(String log) {        if (DEBUG) {            Log.d(TAG, log);        }    }}

- 完整代码在这里

0 0