Platform: RK3399
OS: Android 7.1.1
无法使用红外遥控/蓝牙遥控对主界面进行遥控操作
From 2ed2bd901f5273a124f35577ef0a10266ae86686 Mon Sep 17 00:00:00 2001
From: sjf <sjf@t-chip.com.cn>
Date: Thu, 7 Nov 2019 11:40:52 +0800
Subject: [PATCH] =?UTF-8?q?Android->Launcher:1.=E9=9A=90=E8=97=8F=E6=90=9C?=
=?UTF-8?q?=E7=B4=A2=E6=A0=8F;2.=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B?=
=?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=85=8D=E7=BD=AE=E9=A1=B9;3.=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8Dall=E3=80=80apps=E7=95=8C=E9=9D=A2=E6=97=A0=E6=B3=95?=
=?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=81=A5=E6=8E=A7=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../com/android/launcher3/BaseRecyclerView.java | 2 +-
.../com/android/launcher3/CustomRecyclerView.java | 398 +++++++++++++++++++++
4 files changed, 404 insertions(+), 5 deletions(-)
create mode 100644 packages/apps/Launcher3/src/com/android/launcher3/CustomRecyclerView.java
diff --git a/packages/apps/Launcher3/src/com/android/launcher3/BaseRecyclerView.java b/packages/apps/Launcher3/src/com/android/launcher3/BaseRecyclerView.java
index 74b9cfa..0dfd340 100644
--- a/packages/apps/Launcher3/src/com/android/launcher3/BaseRecyclerView.java
+++ b/packages/apps/Launcher3/src/com/android/launcher3/BaseRecyclerView.java
@@ -33,7 +33,7 @@ import com.android.launcher3.views.RecyclerViewFastScroller;
* <li> Enable fast scroller.
* </ul>
*/
-public abstract class BaseRecyclerView extends RecyclerView {
+public abstract class BaseRecyclerView extends CustomRecyclerView {
protected RecyclerViewFastScroller mScrollbar;
diff --git a/packages/apps/Launcher3/src/com/android/launcher3/CustomRecyclerView.java b/packages/apps/Launcher3/src/com/android/launcher3/CustomRecyclerView.java
new file mode 100644
index 0000000..edf2aba
--- /dev/null
+++ b/packages/apps/Launcher3/src/com/android/launcher3/CustomRecyclerView.java
@@ -0,0 +1,398 @@
+package com.android.launcher3;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.util.AttributeSet;
+import android.view.FocusFinder;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import android.util.Log;
+
+import java.util.List;
+
+
+/**
+ * author songwenju
+ * email:[email protected]
+ * 针对电视的自定义的RecyclerView,该RecyclerView具有以下功能:
+ * 1.响应五向键,上下左右会跟着移动,并获得焦点,在获得焦点时会抬高
+ * 2.在鼠标hover在条目上时会获得焦点。
+ * 3.添加了条目的点击和长按事件
+ * 4.添加了是否第一个可见条目和是否是最后一个可见条目的方法
+ * 5.在item获得焦点时和失去焦点时,这里有相应的回调方法。
+ */
+public class CustomRecyclerView extends RecyclerView {
+
+ public CustomRecyclerView(Context context) {
+ super(context);
+ }
+
+ public CustomRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ //在recyclerView的move事件情况下,拦截调,只让它响应五向键和左右箭头移动
+ return ev.getAction() == MotionEvent.ACTION_MOVE || super.dispatchTouchEvent(ev);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ int dx = this.getChildAt(0).getWidth();
+ View focusView = this.getFocusedChild();
+ if (focusView != null) {
+ //处理左右方向键移动Item到边之后RecyclerView跟着移动
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ Log.d("sjf", "CustomRecyclerView.KEYCODE_DPAD_RIGHT.");
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ return true;
+ } else {
+ View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
+ Log.d("sjf", "rightView is null:" + (rightView == null));
+ if (rightView != null) {
+ Log.d("sjf", "CustomRecyclerView.requestFocusFromTouch.");
+ rightView.requestFocusFromTouch();
+ return true;
+ } else {
+ this.smoothScrollBy(dx, 0);
+ //移动之后获得焦点,是在scroll方法中处理的。
+ return true;
+ }
+ }
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
+// LogUtil.i(this, "left is null:" + (leftView == null));
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ return true;
+ } else {
+ if (leftView != null) {
+ leftView.requestFocusFromTouch();
+ return true;
+ } else {
+ this.smoothScrollBy(-dx, 0);
+ return true;
+ }
+ }
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ View downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN);
+// LogUtil.i(this, "left is null:" + (leftView == null));
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ return true;
+ } else {
+ if (downView != null) {
+ downView.requestFocusFromTouch();
+ return true;
+ } else {
+ this.smoothScrollBy(-dx, 0);
+ return true;
+ }
+ }
+ case KeyEvent.KEYCODE_DPAD_UP:
+ View upView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
+// LogUtil.i(this, "left is null:" + (leftView == null));
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ return true;
+ } else {
+ if (upView != null) {
+ upView.requestFocusFromTouch();
+ return true;
+ } else {
+ this.smoothScrollBy(-dx, 0);
+ return true;
+ }
+ }
+ }
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public void onScrolled(int dx, int dy) {
+// LogUtil.i(this, "CustomRecyclerView.onScrolled.");
+ super.onScrolled(dx, dy);
+ //响应五向键,在Scroll时去获得下一个焦点
+ final View focusView = this.getFocusedChild();
+ if (focusView != null) {
+ if (dx > 0) {
+ View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
+ if (rightView != null) {
+ rightView.requestFocusFromTouch();
+ }
+ } else {
+ View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
+ if (rightView != null) {
+ rightView.requestFocusFromTouch();
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * 第一个条目是否可见
+ *
+ * @return 可见返回true,不可见返回false
+ */
+ public boolean isFirstItemVisible() {
+ return getFirstPosition() == 0;
+ }
+
+ /**
+ * 第一个条目可见条目的position
+ *
+ * @return 可见返回true,不可见返回false
+ */
+ public int getFirstPosition() {
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager instanceof StaggeredGridLayoutManager) {
+ int[] firstVisibleItems = null;
+ firstVisibleItems = ((StaggeredGridLayoutManager) layoutManager).
+ findFirstCompletelyVisibleItemPositions(firstVisibleItems);
+ return firstVisibleItems[0];
+ } else if (layoutManager instanceof LinearLayoutManager) {
+ return ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
+ }
+ return -1;
+ }
+
+
+ /**
+ * 最后一个条目是否可见
+ *
+ * @param lineNum 行数
+ * @param allItemNum item总数
+ * @return 可见返回true,不可见返回false
+ */
+ public boolean isLastItemVisible(int lineNum, int allItemNum) {
+ int position = getLastPosition();
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager instanceof StaggeredGridLayoutManager) {
+// LogUtil.i(this, "lastVisiblePosition:" + position);
+ boolean isVisible = position >= (allItemNum - lineNum);
+// if (isVisible) {
+// scrollBy(1, 0);
+// }
+ return isVisible;
+ } else if (layoutManager instanceof LinearLayoutManager) {
+ return allItemNum -1 == position;
+ }
+ return false;
+ }
+
+
+ /**
+ * 最后一个条目可见条目的position
+ *
+ * @return 可见返回true,不可见返回false
+ */
+ public int getLastPosition() {
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager instanceof StaggeredGridLayoutManager) {
+ int[] lastVisibleItems = null;
+ lastVisibleItems = ((StaggeredGridLayoutManager) layoutManager).findLastCompletelyVisibleItemPositions(lastVisibleItems);
+ return lastVisibleItems[0];
+ } else if (layoutManager instanceof LinearLayoutManager) {
+ return ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
+ }
+ return -1;
+ }
+
+
+
+ /**
+ * 自定义的RecyclerView Adapter,他实现了hover获得焦点,放大的效果。
+ * 实现了点击事件和长按点击事件。
+ *
+ * @param
+ */
+ public static abstract class CustomAdapter<T> extends Adapter<ViewHolder> {
+ private LayoutInflater mInflater;
+ protected List<T> mData;
+ protected Context mContext;
+
+ public interface OnItemClickListener {
+ void onItemClick(View view, int position);
+
+ void onItemLongClick(View view, int position);
+ }
+
+
+ private OnItemClickListener mListener;
+
+ public void setOnItemClickListener(OnItemClickListener listener) {
+ mListener = listener;
+ }
+
+
+ public CustomAdapter(Context context, List<T> data) {
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
+ mData = data;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+// LogUtil.i(this,"HomeTvAdapter.onCreateViewHolder.");
+ View view = mInflater.inflate(onSetItemLayout(), parent, false);
+ return onSetViewHolder(view);
+ }
+
+ protected abstract ViewHolder onSetViewHolder(View view);
+
+ /**
+ * 设置item的layout
+ *
+ * @return item对应的layout
+ */
+ protected abstract
+ @NonNull
+ int onSetItemLayout();
+
+ @Override
+ public void onBindViewHolder(final ViewHolder holder, final int position) {
+// LogUtil.i(this,"HomeTvAdapter.onBindViewHolder.");
+ onSetItemData(holder, position);
+ //item可以获得焦点,需要设置这个属性。
+ holder.itemView.setFocusable(true);
+ holder.itemView.setOnHoverListener(new View.OnHoverListener() {
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ int what = event.getAction();
+ switch (what) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ RecyclerView recyclerView = (RecyclerView) holder.itemView.getParent();
+ int[] location = new int[2];
+ recyclerView.getLocationOnScreen(location);
+ int x = location[0];
+// LogUtil.i("swj","GalleryAdapter.onHover.x="+x +",width = "+(recyclerView.getWidth()+x));
+ //为了防止滚动冲突,在滚动时候,获取焦点为了显示全,会回滚,这样会导致滚动停止
+ if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
+ //当超出RecyclerView的边缘时不去响应滚动
+ if (event.getRawX() > recyclerView.getWidth() + x || event.getRawX() < x) {
+ return true;
+ }
+ //鼠标进入view,争取到焦点
+ v.requestFocusFromTouch();
+ v.requestFocus();
+// LogUtil.i(this,"HomeTvAdapter.onHover.position:"+position);
+ focusStatus(v, position);
+ }
+ break;
+ case MotionEvent.ACTION_HOVER_MOVE: //鼠标在view上移动
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT: //鼠标离开view
+ normalStatus(v, position);
+ break;
+ }
+ return false;
+ }
+ });
+
+ holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ focusStatus(v, position);
+ } else {
+ normalStatus(v, position);
+ }
+ }
+ });
+
+ if (mListener != null) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mListener.onItemClick(v,position);
+ }
+ });
+
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ mListener.onItemLongClick(v,position);
+ return true;
+ }
+ });
+ }
+ }
+
+ /**
+ * 为Item的内容设置数据
+ *
+ * @param viewHolder viewHolder
+ * @param position 位置
+ */
+ protected abstract void onSetItemData(ViewHolder viewHolder, int position);
+
+ /**
+ * item获得焦点时调用
+ *
+ * @param itemView view
+ * @param position
+ */
+ private void focusStatus(View itemView, int position) {
+ if (itemView == null) {
+ return;
+ }
+ onItemFocus(itemView,position);
+ }
+
+ /**
+ * 当item获得焦点时处理
+ *
+ * @param itemView itemView
+ * @param position
+ */
+ protected abstract void onItemFocus(View itemView, int position);
+
+
+ /**
+ * item失去焦点时
+ *
+ * @param itemView item对应的View
+ * @param position
+ */
+ private void normalStatus(View itemView, int position) {
+ if (itemView == null) {
+ return;
+ }
+
+
+ onItemGetNormal(itemView,position);
+
+ }
+
+ /**
+ * 当条目失去焦点时调用
+ *
+ * @param itemView 条目对应的View
+ */
+ protected abstract void onItemGetNormal(View itemView, int position);
+
+ @Override
+ public int getItemCount() {
+ if (mData != null) {
+ return getCount();
+ } else {
+ return 0;
+ }
+ }
+
+ protected abstract int getCount();
+ }
+}
\ No newline at end of file
2.7.4