开发记录
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;
}
}
}