Android TV开发记录

开发记录

1.seekBar的onStartTrackingTouch() 和 onStopTrackingTouch()失效,因为使用的Key事件,故并不回调上述两个方法。

     /**
     * seekBar在TV上由于没有触摸事件,导致onStartTrackingTouch / onStopTrackingTouch方法失效
     * 使用onKey方法监听seekBar的拖拽和暂停
     *
     * @param v       view
     * @param keyCode keyCode
     * @param event   event
     * @return false
     */
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        int action = event.getAction();
        switch (action) {
            case KeyEvent.ACTION_DOWN:
                if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
                    isDragging = true;
                }
                break;
            case KeyEvent.ACTION_UP:
                isDragging = false;
                if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
                    if (listener != null) {
                        listener.onProgressChanged(sbProgress, sbProgress.getProgress(), true);
                    }
                }
                break;
        }
        return false;
    }

2.解析字幕
在解析字幕,使用readLine()读取字幕记录行,第一行通过Interger.parseInt()方法,出现格式化失败的情况。原因是文件第一行有一个空字符。

/*BufferedReader.readLine()读取第一行会出现bug,首行第一个字符会是一个空字符 */
       char s = line.charAt(0);
       //65279是空字符
       if (s == 65279) {
             if (line.length() > 1) {
                   line = line.substring(1);
             }
       }
       int num = Integer.parseInt(line);
/*BufferedReader.readLine()读取第一行会出现bug,首行第一个字符会是一个空字符 */

3.RecycleView获取选中的条目

    LinearLayoutManager manager = (LinearLayoutManager) recycleView.getLayoutManager();
    int firstVis = manager.findFirstVisibleItemPosition();
    int itemCount = manager.getItemCount();
    int targetPos = Math.max(0, Math.min(itemCount - 1, focusPos)) - firstVis;//获取目标item的位置
    View childAt = recycleView.getChildAt(targetPos);  //目标的子条目View

4.RecycleView上下滑动,获焦条目垂直居中

// 在RecyclerView的源码中,scrollTopPosition和smoothScrollToPosition都是直接调用LayoutManager对应的方法
// code in RecyclerView.java

    public void scrollToPosition(int position) {
        if (mLayoutFrozen) {
            return;
        }
        stopScroll();
        if (mLayout == null) {
            Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
                    "Call setLayoutManager with a non-null argument.");
            return;
        }
        mLayout.scrollToPosition(position);
        awakenScrollBars();
    }

    public void smoothScrollToPosition(int position) {
        if (mLayoutFrozen) {
            return;
        }
        if (mLayout == null) {
            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
                    "Call setLayoutManager with a non-null argument.");
            return;
        }
        mLayout.smoothScrollToPosition(this, mState, position);
    }

我们要做的就是在LayoutManager上做点文章,RecyclerView库为我们提供了LinearSmoothScroller类去实现线性滑动效果,我们只需继承此类,根据需求在重写方法中计算滑动delta值,然后复写LayoutManager的scroll相关方法即可。
以常见的GridLayoutManager为例:

public class CenterScrollGridLayoutManager extends GridLayoutManager {

    private Context context;

    private boolean isInLayout;
    private boolean isScrolling;
    
    /* ... constructors... */
    
    public void smoothScrollToCenter(int position) {
        isScrolling = true;
        RecyclerView.SmoothScroller smoothScroller = new CenterScroller(context);
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
        isScrolling = false;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        smoothScrollToCenter(position);
    }

    // 关键方法 - 焦点改变时触发滚动
    @Override
    public boolean onRequestChildFocus(RecyclerView parent, View child, View focused) {
        if (!isInLayout && !isScrolling) {
            smoothScrollToCenter(getPosition(child));
        }
        return true;
    }

    // 重写此方法用于在数据加载完成时触发滚动到中部
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        isInLayout = true;
        try {
            super.onLayoutChildren(recycler, state);
            if (getFocusedChild() != null &&  !isScrolling) {
                if (getChildCount() - getPosition(getFocusedChild()) >= getSpanCount()) {
                    smoothScrollToCenter(getPosition(getFocusedChild()));
                }
            }
        } catch (IndexOutOfBoundsException ignored) {}
        isInLayout = false;
    }
    // 自定义滚动效果的Scroller
    private class CenterScroller extends LinearSmoothScroller {

        private static final float MILLISECONDS_PER_INCH = 50f; //default is 25f (bigger = slower)

        public CenterScroller(Context context) {
            super(context);
        }
        // 这里计算滚动到中部的偏移量
        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }
        // 滚动速度控制
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    }
}

你可能感兴趣的:(Android TV开发记录)