@quicktvui/ai 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rules/.clinerules +27 -4
- package/rules/.cursorrules +27 -4
- package/rules/.github/copilot-instructions.md +27 -4
- package/rules/.source/hippy/extend_views/CoverFlowHorizontalView.java +203 -0
- package/rules/.source/hippy/extend_views/CoverFlowVerticalView.java +203 -0
- package/rules/.source/hippy/extend_views/CoverFlowViewController.java +195 -0
- package/rules/.source/hippy/extend_views/EngineRootView.java +125 -0
- package/rules/.source/hippy/extend_views/ExtendTag.java +83 -0
- package/rules/.source/hippy/extend_views/FocusSearchHelper.java +124 -0
- package/rules/.source/hippy/extend_views/IRecyclerItemView.java +12 -0
- package/rules/.source/hippy/extend_views/JSEventHandleView.java +5 -0
- package/rules/.source/hippy/extend_views/MarqueeRelayManager.java +133 -0
- package/rules/.source/hippy/extend_views/MarqueeRelayTextView.java +211 -0
- package/rules/.source/hippy/extend_views/ProgressBarView.java +83 -0
- package/rules/.source/hippy/extend_views/ProgressBarViewController.java +145 -0
- package/rules/.source/hippy/extend_views/SeekBarView.java +104 -0
- package/rules/.source/hippy/extend_views/SeekBarViewController.java +218 -0
- package/rules/.source/hippy/extend_views/StateImageView.java +149 -0
- package/rules/.source/hippy/extend_views/StateImageViewController.java +34 -0
- package/rules/.source/hippy/extend_views/TVButtonView.java +314 -0
- package/rules/.source/hippy/extend_views/TVButtonViewController.java +89 -0
- package/rules/.source/hippy/extend_views/TVTextView.java +684 -0
- package/rules/.source/hippy/extend_views/TVViewActor.java +811 -0
- package/rules/.source/hippy/extend_views/TVViewActorHost.java +6 -0
- package/rules/.source/hippy/extend_views/TVViewActor/346/216/245/345/205/245.md +66 -0
- package/rules/.source/hippy/extend_views/TemplateUtil.java +336 -0
- package/rules/.source/hippy/extend_views/TextButtonNode.java +47 -0
- package/rules/.source/hippy/extend_views/TextViewController.java +377 -0
- package/rules/.source/hippy/extend_views/fastlist/CenterFlyInAnimator.java +96 -0
- package/rules/.source/hippy/extend_views/fastlist/ChildOnScreenScroller.java +548 -0
- package/rules/.source/hippy/extend_views/fastlist/ClonedViewTag.java +17 -0
- package/rules/.source/hippy/extend_views/fastlist/EventDeliverer.java +55 -0
- package/rules/.source/hippy/extend_views/fastlist/FastAdapter.java +4683 -0
- package/rules/.source/hippy/extend_views/fastlist/FastAdapterUtil.java +982 -0
- package/rules/.source/hippy/extend_views/fastlist/FastFlexNode.java +48 -0
- package/rules/.source/hippy/extend_views/fastlist/FastFlexView.java +873 -0
- package/rules/.source/hippy/extend_views/fastlist/FastFlexViewController.java +130 -0
- package/rules/.source/hippy/extend_views/fastlist/FastItemNode.java +67 -0
- package/rules/.source/hippy/extend_views/fastlist/FastItemView.java +306 -0
- package/rules/.source/hippy/extend_views/fastlist/FastItemViewController.java +106 -0
- package/rules/.source/hippy/extend_views/fastlist/FastListModule.java +95 -0
- package/rules/.source/hippy/extend_views/fastlist/FastListNode.java +90 -0
- package/rules/.source/hippy/extend_views/fastlist/FastListView.java +2466 -0
- package/rules/.source/hippy/extend_views/fastlist/FastListViewController.java +1038 -0
- package/rules/.source/hippy/extend_views/fastlist/FastListView/346/270/262/346/237/223/346/265/201/347/250/213/345/233/276.graffle +0 -0
- package/rules/.source/hippy/extend_views/fastlist/FastPendingView.java +47 -0
- package/rules/.source/hippy/extend_views/fastlist/ItemDecorations.java +71 -0
- package/rules/.source/hippy/extend_views/fastlist/ItemStoreNode.java +64 -0
- package/rules/.source/hippy/extend_views/fastlist/ItemStoreView.java +13 -0
- package/rules/.source/hippy/extend_views/fastlist/ItemStoreViewController.java +45 -0
- package/rules/.source/hippy/extend_views/fastlist/ListItemHolder.java +7 -0
- package/rules/.source/hippy/extend_views/fastlist/ListViewControlProp.java +41 -0
- package/rules/.source/hippy/extend_views/fastlist/MouseRecycleView.java +509 -0
- package/rules/.source/hippy/extend_views/fastlist/OnFastItemClickListener.java +12 -0
- package/rules/.source/hippy/extend_views/fastlist/OnFastItemFocusChangeListener.java +9 -0
- package/rules/.source/hippy/extend_views/fastlist/OnFastScrollStateChangedListener.java +7 -0
- package/rules/.source/hippy/extend_views/fastlist/PendingListNode.java +18 -0
- package/rules/.source/hippy/extend_views/fastlist/PendingViewController.java +13 -0
- package/rules/.source/hippy/extend_views/fastlist/PostHandlerView.java +6 -0
- package/rules/.source/hippy/extend_views/fastlist/PostTaskHolder.java +20 -0
- package/rules/.source/hippy/extend_views/fastlist/ReplaceChildController.java +105 -0
- package/rules/.source/hippy/extend_views/fastlist/ReplaceChildView.java +312 -0
- package/rules/.source/hippy/extend_views/fastlist/TVListView.java +3692 -0
- package/rules/.source/hippy/extend_views/fastlist/TemplateCodeParser.java +247 -0
- package/rules/.source/hippy/extend_views/fastlist/Utils.java +572 -0
- package/rules/.source/hippy/extend_views/fastlist/ViewTag.java +317 -0
- package/rules/.source/hippy/extend_views/fastlist/VirtualListView.java +8 -0
- package/rules/.source/hippy/extend_views/fastlist/diff/FastListDataBindingHelper.java +320 -0
- package/rules/.source/hippy/extend_views/fastlist/diff/KeyDiffHelper.java +289 -0
- package/rules/.source/hippy/extend_views/fastlist/diff/NoKeyDiffHelper.java +278 -0
- package/rules/.source/hippy/extend_views/tag/FontTag.java +53 -0
- package/rules/.source/hippy/extend_views/tag/HtmlTag.java +191 -0
- package/rules/.source/hippy/extend_views/tag/HtmlTagHandler.java +185 -0
- package/rules/.source/hippy/extend_views/tag/SpanTag.java +160 -0
- package/rules/.source/hippy/extend_views/tag/TextFontSpan.java +102 -0
- package/rules/.source/hippy/extend_views/waterfall/Chunk.java +10 -0
- package/rules/.source/hippy/extend_views/waterfall/ChunkGroup.java +5 -0
- package/rules/.source/hippy/extend_views/waterfall/Section.java +4 -0
- package/rules/.source/hippy/extend_views/waterfall/Tabs.java +5 -0
- package/rules/.source/hippy/extend_views/waterfall/WaterfallUtils.java +26 -0
- package/rules/.source/hippy/hippy_uimanager/ControllerHolder.java +30 -0
- package/rules/.source/hippy/hippy_uimanager/ControllerManager.java +651 -0
- package/rules/.source/hippy/hippy_uimanager/ControllerRegistry.java +102 -0
- package/rules/.source/hippy/hippy_uimanager/ControllerUpdateManger.java +252 -0
- package/rules/.source/hippy/hippy_uimanager/CustomControllerHelper.java +425 -0
- package/rules/.source/hippy/hippy_uimanager/DiffUtils.java +526 -0
- package/rules/.source/hippy/hippy_uimanager/ExtendViewGroup.java +36 -0
- package/rules/.source/hippy/hippy_uimanager/HippyCustomViewCreator.java +29 -0
- package/rules/.source/hippy/hippy_uimanager/HippyGroupController.java +83 -0
- package/rules/.source/hippy/hippy_uimanager/HippyViewBase.java +27 -0
- package/rules/.source/hippy/hippy_uimanager/HippyViewController.java +2189 -0
- package/rules/.source/hippy/hippy_uimanager/HippyViewEvent.java +52 -0
- package/rules/.source/hippy/hippy_uimanager/IHippyZIndexViewGroup.java +24 -0
- package/rules/.source/hippy/hippy_uimanager/InternalExtendViewUtil.java +395 -0
- package/rules/.source/hippy/hippy_uimanager/ListItemRenderNode.java +143 -0
- package/rules/.source/hippy/hippy_uimanager/ListViewRenderNode.java +44 -0
- package/rules/.source/hippy/hippy_uimanager/MatrixUtil.java +470 -0
- package/rules/.source/hippy/hippy_uimanager/NativeGestureDispatcher.java +349 -0
- package/rules/.source/hippy/hippy_uimanager/NativeGestureProcessor.java +188 -0
- package/rules/.source/hippy/hippy_uimanager/PullFooterRenderNode.java +43 -0
- package/rules/.source/hippy/hippy_uimanager/PullHeaderRenderNode.java +43 -0
- package/rules/.source/hippy/hippy_uimanager/RenderManager.java +304 -0
- package/rules/.source/hippy/hippy_uimanager/RenderNode.java +533 -0
- package/rules/.source/hippy/hippy_uimanager/StateView.java +17 -0
- package/rules/.source/hippy/hippy_uimanager/TransformUtil.java +125 -0
- package/rules/.source/hippy/hippy_uimanager/ViewGroupDrawingOrderHelper.java +108 -0
- package/rules/.source/hippy/hippy_uimanager/ViewStateProvider.java +10 -0
- package/rules/.source/hippy/hippy_views/audioview/AudioPlayManager.java +457 -0
- package/rules/.source/hippy/hippy_views/audioview/AudioView.java +225 -0
- package/rules/.source/hippy/hippy_views/audioview/AudioViewController.java +135 -0
- package/rules/.source/hippy/hippy_views/common/CommonBackgroundDrawable.java +58 -0
- package/rules/.source/hippy/hippy_views/common/CommonBorder.java +37 -0
- package/rules/.source/hippy/hippy_views/custom/HippyCustomPropsController.java +61 -0
- package/rules/.source/hippy/hippy_views/hippylist/HippyRecyclerListAdapter.java +399 -0
- package/rules/.source/hippy/hippy_views/hippylist/HippyRecyclerView.java +378 -0
- package/rules/.source/hippy/hippy_views/hippylist/HippyRecyclerViewController.java +187 -0
- package/rules/.source/hippy/hippy_views/hippylist/HippyRecyclerViewHolder.java +39 -0
- package/rules/.source/hippy/hippy_views/hippylist/HippyRecyclerViewWrapper.java +134 -0
- package/rules/.source/hippy/hippy_views/hippylist/NodePositionHelper.java +55 -0
- package/rules/.source/hippy/hippy_views/hippylist/PreloadHelper.java +54 -0
- package/rules/.source/hippy/hippy_views/hippylist/PullFooterEventHelper.java +61 -0
- package/rules/.source/hippy/hippy_views/hippylist/PullHeaderEventHelper.java +127 -0
- package/rules/.source/hippy/hippy_views/hippylist/RecyclerViewEventHelper.java +394 -0
- package/rules/.source/hippy/hippy_views/image/HippyContentDrawable.java +113 -0
- package/rules/.source/hippy/hippy_views/image/HippyImageView.java +1608 -0
- package/rules/.source/hippy/hippy_views/image/HippyImageViewController.java +382 -0
- package/rules/.source/hippy/hippy_views/image/IImageStateListener.java +7 -0
- package/rules/.source/hippy/hippy_views/list/ChildOnScreenScroller.java +255 -0
- package/rules/.source/hippy/hippy_views/list/HippyListAdapter.java +647 -0
- package/rules/.source/hippy/hippy_views/list/HippyListItemView.java +162 -0
- package/rules/.source/hippy/hippy_views/list/HippyListItemViewController.java +45 -0
- package/rules/.source/hippy/hippy_views/list/HippyListView.java +915 -0
- package/rules/.source/hippy/hippy_views/list/HippyListViewController.java +622 -0
- package/rules/.source/hippy/hippy_views/list/HippyRecycler.java +31 -0
- package/rules/.source/hippy/hippy_views/list/IRecycleItemTypeChange.java +23 -0
- package/rules/.source/hippy/hippy_views/list/ItemDecorations.java +70 -0
- package/rules/.source/hippy/hippy_views/list/NegativeLongKeyFlinger.java +156 -0
- package/rules/.source/hippy/hippy_views/list/NodeHolder.java +34 -0
- package/rules/.source/hippy/hippy_views/list/RecycleViewFlinger.java +126 -0
- package/rules/.source/hippy/hippy_views/list/TVRecyclerView.java +2070 -0
- package/rules/.source/hippy/hippy_views/list/TVSingleLineListView.java +15 -0
- package/rules/.source/hippy/hippy_views/modal/HippyModalHostManager.java +102 -0
- package/rules/.source/hippy/hippy_views/modal/HippyModalHostView.java +597 -0
- package/rules/.source/hippy/hippy_views/modal/ModalHostHelper.java +46 -0
- package/rules/.source/hippy/hippy_views/modal/ModalStyleNode.java +34 -0
- package/rules/.source/hippy/hippy_views/modal/RequestCloseEvent.java +32 -0
- package/rules/.source/hippy/hippy_views/modal/ShowEvent.java +31 -0
- package/rules/.source/hippy/hippy_views/navigator/Navigator.java +126 -0
- package/rules/.source/hippy/hippy_views/navigator/NavigatorController.java +120 -0
- package/rules/.source/hippy/hippy_views/refresh/HippyPullFooterView.java +47 -0
- package/rules/.source/hippy/hippy_views/refresh/HippyPullFooterViewController.java +65 -0
- package/rules/.source/hippy/hippy_views/refresh/HippyPullHeaderView.java +39 -0
- package/rules/.source/hippy/hippy_views/refresh/HippyPullHeaderViewController.java +104 -0
- package/rules/.source/hippy/hippy_views/refresh/RefreshWrapper.java +237 -0
- package/rules/.source/hippy/hippy_views/refresh/RefreshWrapperController.java +62 -0
- package/rules/.source/hippy/hippy_views/refresh/RefreshWrapperItemController.java +39 -0
- package/rules/.source/hippy/hippy_views/refresh/RefreshWrapperItemView.java +26 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyHorizontalScrollView.java +500 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyOnScrollHelper.java +39 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyScrollView.java +46 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyScrollViewController.java +178 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyScrollViewEventHelper.java +92 -0
- package/rules/.source/hippy/hippy_views/scroll/HippyVerticalScrollView.java +522 -0
- package/rules/.source/hippy/hippy_views/text/HippyTextView.java +512 -0
- package/rules/.source/hippy/hippy_views/text/HippyTextViewController.java +77 -0
- package/rules/.source/hippy/hippy_views/textinput/HippyTextInput.java +668 -0
- package/rules/.source/hippy/hippy_views/textinput/HippyTextInputController.java +528 -0
- package/rules/.source/hippy/hippy_views/textinput/TextInputNode.java +115 -0
- package/rules/.source/hippy/hippy_views/videoview/APEZProvider.java +287 -0
- package/rules/.source/hippy/hippy_views/videoview/APKExpansionSupport.java +82 -0
- package/rules/.source/hippy/hippy_views/videoview/PivotPoint.java +13 -0
- package/rules/.source/hippy/hippy_views/videoview/ScalableType.java +34 -0
- package/rules/.source/hippy/hippy_views/videoview/ScalableVideoView.java +265 -0
- package/rules/.source/hippy/hippy_views/videoview/ScaleManager.java +191 -0
- package/rules/.source/hippy/hippy_views/videoview/Size.java +19 -0
- package/rules/.source/hippy/hippy_views/videoview/VideoHippyView.java +917 -0
- package/rules/.source/hippy/hippy_views/videoview/VideoHippyViewController.java +236 -0
- package/rules/.source/hippy/hippy_views/videoview/ZipResourceFile.java +427 -0
- package/rules/.source/hippy/hippy_views/view/CardRootView.java +28 -0
- package/rules/.source/hippy/hippy_views/view/CustomLayoutView.java +10 -0
- package/rules/.source/hippy/hippy_views/view/CustomNodeView.java +5 -0
- package/rules/.source/hippy/hippy_views/view/DialogViewGroup.java +113 -0
- package/rules/.source/hippy/hippy_views/view/HippyViewGroup.java +2042 -0
- package/rules/.source/hippy/hippy_views/view/HippyViewGroupController.java +583 -0
- package/rules/.source/hippy/hippy_views/view/WindowRoot.java +5 -0
- package/rules/.source/hippy/hippy_views/viewpager/HippyViewPager.java +308 -0
- package/rules/.source/hippy/hippy_views/viewpager/HippyViewPagerAdapter.java +148 -0
- package/rules/.source/hippy/hippy_views/viewpager/HippyViewPagerController.java +246 -0
- package/rules/.source/hippy/hippy_views/viewpager/HippyViewPagerItem.java +27 -0
- package/rules/.source/hippy/hippy_views/viewpager/HippyViewPagerItemController.java +42 -0
- package/rules/.source/hippy/hippy_views/viewpager/ViewPagerPageChangeListener.java +114 -0
- package/rules/.source/hippy/hippy_views/viewpager/event/HippyPageItemExposureEvent.java +40 -0
- package/rules/.source/hippy/hippy_views/viewpager/event/HippyPageScrollEvent.java +43 -0
- package/rules/.source/hippy/hippy_views/viewpager/event/HippyPageScrollStateChangedEvent.java +42 -0
- package/rules/.source/hippy/hippy_views/viewpager/event/HippyPageSelectedEvent.java +42 -0
- package/rules/.source/hippy/hippy_views/webview/HippyWebView.java +160 -0
- package/rules/.source/hippy/hippy_views/webview/HippyWebViewBridge.java +20 -0
- package/rules/.source/hippy/hippy_views/webview/HippyWebViewController.java +103 -0
- package/rules/.source/hippy/hippy_views/webview/HippyWebViewInner.java +77 -0
- package/rules/.windsurfrules +27 -4
- package/rules/AGENTS.md +27 -4
- package/rules/CLAUDE.md +27 -3
- package/rules/GEMINI.md +25 -3
|
@@ -0,0 +1,2070 @@
|
|
|
1
|
+
package com.tencent.mtt.hippy.views.list;
|
|
2
|
+
|
|
3
|
+
import android.animation.Animator;
|
|
4
|
+
import android.animation.AnimatorListenerAdapter;
|
|
5
|
+
import android.animation.ObjectAnimator;
|
|
6
|
+
import android.content.Context;
|
|
7
|
+
import android.graphics.Canvas;
|
|
8
|
+
import android.graphics.PointF;
|
|
9
|
+
import android.graphics.Rect;
|
|
10
|
+
import android.os.Build;
|
|
11
|
+
import android.util.Log;
|
|
12
|
+
import android.view.FocusFinder;
|
|
13
|
+
import android.view.KeyEvent;
|
|
14
|
+
import android.view.View;
|
|
15
|
+
import android.view.ViewGroup;
|
|
16
|
+
import android.view.ViewTreeObserver;
|
|
17
|
+
import android.view.animation.CycleInterpolator;
|
|
18
|
+
|
|
19
|
+
import android.support.annotation.NonNull;
|
|
20
|
+
import android.support.annotation.Nullable;
|
|
21
|
+
|
|
22
|
+
import com.tencent.extend.AnimationStore;
|
|
23
|
+
import com.tencent.extend.AutoFocusManager;
|
|
24
|
+
import com.tencent.extend.ITVView;
|
|
25
|
+
import com.tencent.extend.StateListPresenter;
|
|
26
|
+
import com.tencent.extend.TVViewUtil;
|
|
27
|
+
import com.tencent.extend.TriggerTaskHost;
|
|
28
|
+
import com.tencent.extend.TriggerTaskManagerModule;
|
|
29
|
+
import com.tencent.extend.views.fastlist.ListViewControlProp;
|
|
30
|
+
import com.tencent.extend.views.fastlist.Utils;
|
|
31
|
+
import com.tencent.mtt.hippy.FocusDispatchView;
|
|
32
|
+
import com.tencent.mtt.hippy.HippyEngineContext;
|
|
33
|
+
import com.tencent.mtt.hippy.common.HippyArray;
|
|
34
|
+
import com.tencent.mtt.hippy.common.HippyMap;
|
|
35
|
+
import com.tencent.mtt.hippy.uimanager.ControllerManager;
|
|
36
|
+
import com.tencent.mtt.hippy.uimanager.ExtendViewGroup;
|
|
37
|
+
import com.tencent.mtt.hippy.uimanager.HippyViewEvent;
|
|
38
|
+
import com.tencent.mtt.hippy.uimanager.InternalExtendViewUtil;
|
|
39
|
+
import com.tencent.mtt.hippy.uimanager.RenderNode;
|
|
40
|
+
import com.tencent.mtt.hippy.uimanager.ViewStateProvider;
|
|
41
|
+
import com.tencent.mtt.hippy.utils.ExtendUtil;
|
|
42
|
+
import com.tencent.mtt.hippy.utils.LogUtils;
|
|
43
|
+
import com.tencent.mtt.supportui.views.recyclerview.BaseLayoutManager;
|
|
44
|
+
import com.tencent.mtt.supportui.views.recyclerview.LinearLayoutManager;
|
|
45
|
+
import com.tencent.mtt.supportui.views.recyclerview.LinearSmoothScroller;
|
|
46
|
+
import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase;
|
|
47
|
+
import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem;
|
|
48
|
+
|
|
49
|
+
import java.util.ArrayList;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
public class TVRecyclerView extends HippyListView implements ExtendViewGroup, TriggerTaskHost, RecycleViewFlinger.IRecyclerView, TVSingleLineListView, ViewStateProvider {
|
|
53
|
+
|
|
54
|
+
protected SingleLineLayoutManager singleLineLayoutManager;
|
|
55
|
+
|
|
56
|
+
protected int orientation = HORIZONTAL;
|
|
57
|
+
|
|
58
|
+
FocusEventListener mFocusListener;
|
|
59
|
+
|
|
60
|
+
ChildOnScreenScroller mCustomChildOnScreenScroller;
|
|
61
|
+
|
|
62
|
+
protected int defaultSectionPosition = -1;
|
|
63
|
+
protected int mTargetFocusChildPosition = -1;
|
|
64
|
+
|
|
65
|
+
protected int activatedPosition = -1;
|
|
66
|
+
|
|
67
|
+
protected boolean disableFocusIntercept = false;
|
|
68
|
+
|
|
69
|
+
protected int mFocusChildPosition = 0;
|
|
70
|
+
|
|
71
|
+
public final static String TAG = "DebugHippyList";
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
private Rect clipOutset;
|
|
75
|
+
|
|
76
|
+
private boolean enableFocusMemory = true;
|
|
77
|
+
|
|
78
|
+
private int[] mBlockFocusOnFail;
|
|
79
|
+
private int[] mBlockFocus;
|
|
80
|
+
|
|
81
|
+
private int initFocusPositionAfterLayout = -1;
|
|
82
|
+
public static final int REQUEST_CHILD_ON_SCREEN_TYPE_CENTER = 0;
|
|
83
|
+
public static final int REQUEST_CHILD_ON_SCREEN_TYPE_NONE = 2;
|
|
84
|
+
public static final int REQUEST_CHILD_ON_SCREEN_TYPE_ANDROID = 1;
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
private boolean enableSelectOnFocus = true;
|
|
88
|
+
|
|
89
|
+
protected boolean mShakeEndEnable = true;
|
|
90
|
+
|
|
91
|
+
boolean useAdvancedFocusSearch = true;
|
|
92
|
+
|
|
93
|
+
private boolean isUseNegativeLayout = false;
|
|
94
|
+
|
|
95
|
+
private ItemDecoration blankItemDecoration;
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
protected Animator mShakeEndAnimator;
|
|
99
|
+
|
|
100
|
+
private InitParams mInitParams;
|
|
101
|
+
private boolean forceBlockFocusOnFail = false;
|
|
102
|
+
|
|
103
|
+
private View currentFocusView;
|
|
104
|
+
|
|
105
|
+
public void setForceBlockFocusOnFail(boolean forceBlockFocusOnFail) {
|
|
106
|
+
this.forceBlockFocusOnFail = forceBlockFocusOnFail;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
public void setEnableSelectOnFocus(boolean enableSelectOnFocus) {
|
|
111
|
+
this.enableSelectOnFocus = enableSelectOnFocus;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public void setUseAdvancedFocusSearch(boolean useAdvancedFocusSearch) {
|
|
115
|
+
this.useAdvancedFocusSearch = useAdvancedFocusSearch;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public void setUseNegativeLayout(boolean useNegativeLayout) {
|
|
119
|
+
isUseNegativeLayout = useNegativeLayout;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private boolean mListenFocusSearchOnFail = false;
|
|
123
|
+
private boolean mListenBoundEvent = false;
|
|
124
|
+
|
|
125
|
+
public void setListenBoundEvent(boolean mListenBoundEvent) {
|
|
126
|
+
this.mListenBoundEvent = mListenBoundEvent;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public boolean isListenBoundEvent() {
|
|
130
|
+
return mListenBoundEvent;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public void setListenFocusSearchOnFail(boolean mListenFocusSearchOnFail) {
|
|
134
|
+
this.mListenFocusSearchOnFail = mListenFocusSearchOnFail;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
public void setShakeEndEnable(boolean shakeEndEnable) {
|
|
139
|
+
this.mShakeEndEnable = shakeEndEnable;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public void setBlockFocusOnFail(int[] directions) {
|
|
143
|
+
this.mBlockFocusOnFail = directions;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@Override
|
|
147
|
+
public void diffSetScrollToPosition(int position, int offset) {
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public void setBlockFocusOn(int[] directions) {
|
|
152
|
+
this.mBlockFocus = directions;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public void setRequestChildOnScreenType(int requestChildOnScreenType) {
|
|
156
|
+
if (getSingleLineLayoutManager().childOnScreenScroller != null) {
|
|
157
|
+
getSingleLineLayoutManager().childOnScreenScroller.setType(requestChildOnScreenType);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public void setRequestChildOnScreenClampBackward(int clampBackward) {
|
|
162
|
+
if (getSingleLineLayoutManager().childOnScreenScroller != null) {
|
|
163
|
+
getSingleLineLayoutManager().childOnScreenScroller.setClampBackward(clampBackward);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public void setRequestChildOnScreenClampForward(int clampForward) {
|
|
168
|
+
if (getSingleLineLayoutManager().childOnScreenScroller != null) {
|
|
169
|
+
getSingleLineLayoutManager().childOnScreenScroller.setClampForward(clampForward);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public void setScrollThresholdVertical(int threshold) {
|
|
174
|
+
if (getSingleLineLayoutManager().childOnScreenScroller != null) {
|
|
175
|
+
getSingleLineLayoutManager().childOnScreenScroller.setScrollThresholdVertical(threshold);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public void setScrollThresholdHorizontal(int threshold) {
|
|
180
|
+
if (getSingleLineLayoutManager().childOnScreenScroller != null) {
|
|
181
|
+
getSingleLineLayoutManager().childOnScreenScroller.setScrollThresholdHorizontal(threshold);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public void setBlankItemDecoration(HippyArray array) {
|
|
186
|
+
if (blankItemDecoration != null) {
|
|
187
|
+
removeItemDecoration(blankItemDecoration);
|
|
188
|
+
}
|
|
189
|
+
final int head = array.getInt(0);
|
|
190
|
+
final int end = array.getInt(1);
|
|
191
|
+
if (LogUtils.isDebug()) {
|
|
192
|
+
LogUtils.d(TAG, "setBlankItemDecoration vertical head:" + head + ",end:" + end);
|
|
193
|
+
}
|
|
194
|
+
blankItemDecoration = new ItemDecoration() {
|
|
195
|
+
@Override
|
|
196
|
+
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerViewBase parent) {
|
|
197
|
+
super.getItemOffsets(outRect, itemPosition, parent);
|
|
198
|
+
if (getOrientation() == VERTICAL) {
|
|
199
|
+
if (itemPosition == 0) {
|
|
200
|
+
outRect.top = head;
|
|
201
|
+
} else if (itemPosition == parent.getLayoutManager().getItemCount() - 1) {
|
|
202
|
+
outRect.bottom = end;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
if (itemPosition == 0) {
|
|
206
|
+
outRect.left = head;
|
|
207
|
+
} else if (itemPosition == parent.getLayoutManager().getItemCount() - 1) {
|
|
208
|
+
outRect.right = end;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
addItemDecoration(blankItemDecoration);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@Override
|
|
217
|
+
public void getState(@NonNull HippyMap map) {
|
|
218
|
+
map.pushInt(Utils.ORIENTATION, getOrientation());
|
|
219
|
+
map.pushInt(Utils.ITEMCOUNT, getAdapter() != null ? getAdapter().getItemCount() : 0);
|
|
220
|
+
map.pushInt(Utils.FOCUS_POSITION, getFocusedChild() != null ? getChildPosition(getFocusedChild()) : -1);
|
|
221
|
+
map.pushInt(Utils.SELECT_POSITION, getSelectChildPosition());
|
|
222
|
+
map.pushInt(Utils.OFFSETX, getOffsetX());
|
|
223
|
+
map.pushInt(Utils.OFFSETY, getOffsetY());
|
|
224
|
+
map.pushInt(Utils.SCROLLSTATE, getScrollState());
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
public interface OnLayoutManagerCallback {
|
|
228
|
+
void onLayoutCompleted(State state);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public void setInitFocusPositionAfterLayout(int requestFocusPositionAfterLayout) {
|
|
232
|
+
this.initFocusPositionAfterLayout = requestFocusPositionAfterLayout;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public void enableFocusMemory(boolean enableFocusMemory) {
|
|
236
|
+
this.enableFocusMemory = enableFocusMemory;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@Override
|
|
241
|
+
public void setListData() {
|
|
242
|
+
|
|
243
|
+
//zhaopeng 防止列表刷新过多的item
|
|
244
|
+
if (isUseNegativeLayout) {
|
|
245
|
+
final HippyEngineContext context = getHippyContext();
|
|
246
|
+
if (context != null) {
|
|
247
|
+
final RenderNode node = context.getRenderManager().getRenderNode(getId());
|
|
248
|
+
if (node != null) {
|
|
249
|
+
final int totalCount = node.getChildCount();
|
|
250
|
+
final int lastItemPosition = getSingleLineLayoutManager().findLastCompletelyVisibleItemPosition();
|
|
251
|
+
|
|
252
|
+
if (totalCount > 0 && lastItemPosition > -1 && lastItemPosition < totalCount - 1) {
|
|
253
|
+
final int diff = totalCount - lastItemPosition;
|
|
254
|
+
getListAdapter().notifyItemRangeChanged(lastItemPosition + 1, diff);
|
|
255
|
+
dispatchLayout();
|
|
256
|
+
Log.e(TAG, "setListData : notifyItemRangeChanged ->>>totalCount :" + totalCount + ",lastItemPosition:" + lastItemPosition + ",diff:" + diff);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (LogUtils.isDebug()) {
|
|
263
|
+
Log.e("PendingFocus", "###########setListData########## pendingWork:" + mInitParams + ",id:" + getId());
|
|
264
|
+
}
|
|
265
|
+
super.setListData();
|
|
266
|
+
if (mInitParams != null) {
|
|
267
|
+
if (LogUtils.isDebug()) {
|
|
268
|
+
Log.d("PendingFocus", "after setListData scrollToPosition:" + mInitParams + ",id:" + getId());
|
|
269
|
+
}
|
|
270
|
+
scrollToPosition(mInitParams.scrollToPosition, mInitParams.scrollOffset);
|
|
271
|
+
// RenderUtil.requestNodeLayout(this);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@Override
|
|
277
|
+
protected int getScrollToPosition() {
|
|
278
|
+
return mInitParams == null ? -1 : mInitParams.scrollToPosition;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@Override
|
|
282
|
+
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
|
283
|
+
super.onWindowFocusChanged(hasWindowFocus);
|
|
284
|
+
if (LogUtils.isDebug()) {
|
|
285
|
+
Log.d("SingleLineRecyclerView", "onWindowVisibilityChanged onWindowFocusChanged:" + hasWindowFocus);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
@Override
|
|
290
|
+
protected void onWindowVisibilityChanged(int visibility) {
|
|
291
|
+
super.onWindowVisibilityChanged(visibility);
|
|
292
|
+
if (LogUtils.isDebug()) {
|
|
293
|
+
Log.d("SingleLineRecyclerView", "onWindowVisibilityChanged visibility:" + visibility);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@Override
|
|
298
|
+
protected void onAttachedToWindow() {
|
|
299
|
+
super.onAttachedToWindow();
|
|
300
|
+
if (LogUtils.isDebug()) {
|
|
301
|
+
Log.d("SingleLineRecyclerView", "onAttachedToWindow");
|
|
302
|
+
}
|
|
303
|
+
listenGlobalFocusChangeIfNeed();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
Rect temp;
|
|
308
|
+
|
|
309
|
+
@Override
|
|
310
|
+
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
311
|
+
super.onLayout(changed, l, t, r, b);
|
|
312
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
|
313
|
+
if (clipOutset != null) {
|
|
314
|
+
if (temp == null) {
|
|
315
|
+
temp = new Rect();
|
|
316
|
+
}
|
|
317
|
+
temp.set(-clipOutset.left, -clipOutset.top, getWidth() + clipOutset.right, getHeight() + clipOutset.bottom);
|
|
318
|
+
setClipBounds(temp);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
private View[] mFocusSearchTargets;
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
public void setClipOutset(int left, int top, int right, int bottom) {
|
|
328
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
|
329
|
+
if (clipOutset == null) {
|
|
330
|
+
clipOutset = new Rect();
|
|
331
|
+
}
|
|
332
|
+
clipOutset.set(left, top, right, bottom);
|
|
333
|
+
requestLayout();
|
|
334
|
+
setClipChildren(false);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
public View findSelectedChild() {
|
|
339
|
+
final int select = defaultSectionPosition;
|
|
340
|
+
if (select > -1) {
|
|
341
|
+
return getSingleLineLayoutManager().findViewByPosition(select);
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
public void setActivatedPosition(int activatedPosition) {
|
|
348
|
+
// final int last = activatedPosition;
|
|
349
|
+
this.activatedPosition = activatedPosition;
|
|
350
|
+
|
|
351
|
+
if (getChildCount() > 0) {
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
for (int i = 0; i < getChildCount(); i++) {
|
|
355
|
+
final View child = singleLineLayoutManager.getChildAt(i);
|
|
356
|
+
if (child != null) {
|
|
357
|
+
callItemStateChangeIfNeed(child, child.isFocused() ? StateListPresenter.STATE_FOCUSED : StateListPresenter.STATE_NORMAL);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (activatedPosition > -1) {
|
|
361
|
+
final View newOne = singleLineLayoutManager.findViewByPosition(activatedPosition);
|
|
362
|
+
if (newOne != null) {
|
|
363
|
+
callItemStateChangeIfNeed(newOne, StateListPresenter.STATE_ACTIVATED);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
public void setTargetFocusChildPosition(int mTargetFocusChildPosition) {
|
|
370
|
+
this.mTargetFocusChildPosition = mTargetFocusChildPosition;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
OnLayoutManagerCallback onLayoutManagerCallback;
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
public void setOnLayoutManagerCallback(OnLayoutManagerCallback onLayoutManagerCallback) {
|
|
377
|
+
this.onLayoutManagerCallback = onLayoutManagerCallback;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
public void setChildOnScreenScroller(@Nullable ChildOnScreenScroller scroller) {
|
|
382
|
+
this.mCustomChildOnScreenScroller = scroller;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private int mScrollOffset = 0;
|
|
386
|
+
|
|
387
|
+
public TVRecyclerView(Context context, int orientation) {
|
|
388
|
+
super(context, orientation);
|
|
389
|
+
this.orientation = orientation;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
public TVRecyclerView(Context context) {
|
|
393
|
+
this(context, BaseLayoutManager.VERTICAL);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
public int getOrientation() {
|
|
398
|
+
return orientation;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@Override
|
|
402
|
+
public void requestChildFocus(View child, View focused) {
|
|
403
|
+
final View mSelectedChild = findSelectedChild();
|
|
404
|
+
final View lastFocus = mSelectedChild;
|
|
405
|
+
if (mSelectedChild != null) {
|
|
406
|
+
callItemStateChangeIfNeed(lastFocus, StateListPresenter.STATE_NORMAL);
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
super.requestChildFocus(child, focused);
|
|
410
|
+
if (mEnableChildFocusEvent) {
|
|
411
|
+
if (mChildFocusEvent == null) {
|
|
412
|
+
mChildFocusEvent = new HippyViewEvent(InternalExtendViewUtil.CHILD_FOCUS_EVENT_NAME);
|
|
413
|
+
}
|
|
414
|
+
InternalExtendViewUtil.sendEventOnRequestChildFocus(this, child, focused, mChildFocusEvent);
|
|
415
|
+
}
|
|
416
|
+
} catch (Throwable t) {
|
|
417
|
+
Log.e(TAG, "requestChildFocus error :" + t.getMessage() + " focused:" + focused);
|
|
418
|
+
t.printStackTrace();
|
|
419
|
+
}
|
|
420
|
+
callItemStateChangeIfNeed(child, StateListPresenter.STATE_FOCUSED);
|
|
421
|
+
final int focusedChildPosition = getChildPosition(child);
|
|
422
|
+
|
|
423
|
+
changeSelectState(defaultSectionPosition, false);
|
|
424
|
+
if (enableSelectOnFocus) {
|
|
425
|
+
defaultSectionPosition = focusedChildPosition;
|
|
426
|
+
} else {
|
|
427
|
+
changeSelectState(defaultSectionPosition, true);
|
|
428
|
+
}
|
|
429
|
+
mTargetFocusChildPosition = focusedChildPosition;
|
|
430
|
+
mFocusChildPosition = focusedChildPosition;
|
|
431
|
+
currentFocusView = focused;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
void changeSelectState(final int position, boolean select) {
|
|
435
|
+
final View child = findViewByPosition(position);
|
|
436
|
+
if (child != null) {
|
|
437
|
+
changeSelectState(child, select);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
void changeSelectState(View child, boolean select) {
|
|
442
|
+
// if(child != null && child != getFocusedChild()){
|
|
443
|
+
if (child != null) {
|
|
444
|
+
if (select) {
|
|
445
|
+
if (child.isSelected()) {
|
|
446
|
+
child.setSelected(false);
|
|
447
|
+
}
|
|
448
|
+
child.setSelected(true);
|
|
449
|
+
} else {
|
|
450
|
+
child.setSelected(false);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private boolean lockFocusOnLayout = true;
|
|
456
|
+
|
|
457
|
+
public void setLockFocusOnLayout(boolean lockFocusOnLayout) {
|
|
458
|
+
this.lockFocusOnLayout = lockFocusOnLayout;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
public void disableFocusIntercept(boolean disable) {
|
|
462
|
+
this.disableFocusIntercept = disable;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
public void applyChildOnScreenScroller() {
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
public int getSelectChildPosition() {
|
|
469
|
+
return defaultSectionPosition;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
protected void callItemStateChangeIfNeed(View child, int state) {
|
|
473
|
+
if (state == StateListPresenter.STATE_SELECTED) {
|
|
474
|
+
InternalExtendViewUtil.sendEventOnRequestListChildSelect(this, child);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
protected void exeShakeRecycleView() {
|
|
481
|
+
|
|
482
|
+
LogUtils.v(TAG, "exeShakeRecycleView orientation is " + orientation);
|
|
483
|
+
|
|
484
|
+
if (mShakeEndAnimator == null) {
|
|
485
|
+
final Animator shake = AnimationStore.defaultShakeEndAnimator(this, getOrientation());
|
|
486
|
+
mShakeEndAnimator = shake;
|
|
487
|
+
notifyShakeEnd();
|
|
488
|
+
shake.start();
|
|
489
|
+
shake.addListener(new AnimatorListenerAdapter() {
|
|
490
|
+
@Override
|
|
491
|
+
public void onAnimationEnd(Animator animation) {
|
|
492
|
+
super.onAnimationEnd(animation);
|
|
493
|
+
mShakeEndAnimator = null;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
protected boolean exeAnimRunning = false;
|
|
500
|
+
|
|
501
|
+
protected void exeShakeSelf(View view, int direction) {
|
|
502
|
+
if (!exeAnimRunning) {
|
|
503
|
+
exeAnimRunning = true;
|
|
504
|
+
ObjectAnimator shakeSelfAnim;//抖动幅度0到5
|
|
505
|
+
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
|
|
506
|
+
shakeSelfAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y.getName(), 0, 5f);
|
|
507
|
+
} else {
|
|
508
|
+
shakeSelfAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X.getName(), 0, 5f);
|
|
509
|
+
}
|
|
510
|
+
shakeSelfAnim.setDuration(250);//持续时间
|
|
511
|
+
shakeSelfAnim.setInterpolator(new CycleInterpolator(2));//抖动次数
|
|
512
|
+
shakeSelfAnim.addListener(new AnimatorListenerAdapter() {
|
|
513
|
+
@Override
|
|
514
|
+
public void onAnimationCancel(Animator animation) {
|
|
515
|
+
exeAnimRunning = false;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
@Override
|
|
519
|
+
public void onAnimationEnd(Animator animation) {
|
|
520
|
+
exeAnimRunning = false;
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
shakeSelfAnim.start();//开始动画
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
protected void notifyShakeEnd() {
|
|
529
|
+
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* 设置选中的子view,注意此方法只在view已经显示出来以后调用才有效。
|
|
535
|
+
*
|
|
536
|
+
* @param position
|
|
537
|
+
*/
|
|
538
|
+
public void setSelectChildPosition(int position) {
|
|
539
|
+
this.setSelectChildPosition(position, true);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
public void setupInitScrollWork(int position, int scrollToPosition, int offset, String focusName, boolean block, int delay) {
|
|
543
|
+
if (position < 0 && scrollToPosition < 0) {
|
|
544
|
+
clearInitFocusPosition();
|
|
545
|
+
} else {
|
|
546
|
+
mInitParams = new InitParams(position, scrollToPosition, offset, focusName, block, delay);
|
|
547
|
+
if (block) {
|
|
548
|
+
Log.e("PendingFocus", "setPendingFocusChild blockRootFocus!!");
|
|
549
|
+
InternalExtendViewUtil.blockRootFocus(this);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
public void clearInitFocusPosition() {
|
|
556
|
+
if (mInitParams != null) {
|
|
557
|
+
mInitParams.targetFocusPosition = -1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
public void requestTargetFocus(boolean block, int delay, int position, String target) {
|
|
562
|
+
if (block) {
|
|
563
|
+
InternalExtendViewUtil.blockRootFocus(this);
|
|
564
|
+
}
|
|
565
|
+
if (delay > 0) {
|
|
566
|
+
getRootView().postDelayed(() -> {
|
|
567
|
+
if (LogUtils.isDebug()) {
|
|
568
|
+
Log.e("PendingFocus", "setInitPositionInfo found focus requestFocusDirectly!!");
|
|
569
|
+
}
|
|
570
|
+
if (LogUtils.isDebug()) {
|
|
571
|
+
LogUtils.e(FocusDispatchView.TAG, "unBlockRootFocus 1");
|
|
572
|
+
}
|
|
573
|
+
InternalExtendViewUtil.unBlockRootFocus(TVRecyclerView.this);
|
|
574
|
+
if (getSingleLineLayoutManager().requestTargetChildFocus(position, target)) {
|
|
575
|
+
if (LogUtils.isDebug()) {
|
|
576
|
+
Log.e("PendingFocus", "clear mPendingFocus");
|
|
577
|
+
}
|
|
578
|
+
//this.clearInitFocusPosition();
|
|
579
|
+
}
|
|
580
|
+
}, delay);
|
|
581
|
+
} else {
|
|
582
|
+
if (LogUtils.isDebug()) {
|
|
583
|
+
LogUtils.e(FocusDispatchView.TAG, "unBlockRootFocus 2");
|
|
584
|
+
}
|
|
585
|
+
InternalExtendViewUtil.unBlockRootFocus(this);
|
|
586
|
+
if (LogUtils.isDebug()) {
|
|
587
|
+
Log.e("PendingFocus", "setInitPositionInfo found focus requestFocusDirectly!!");
|
|
588
|
+
}
|
|
589
|
+
if (getSingleLineLayoutManager().requestTargetChildFocus(position, target)) {
|
|
590
|
+
if (LogUtils.isDebug()) {
|
|
591
|
+
Log.e("PendingFocus", "clear mPendingFocus");
|
|
592
|
+
}
|
|
593
|
+
//this.clearInitFocusPosition();
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
public void setInitPositionInfo(HippyMap map) {
|
|
600
|
+
/*
|
|
601
|
+
:initPosition=
|
|
602
|
+
{
|
|
603
|
+
// 请求焦点的位置可以不传,不传不会请求焦点
|
|
604
|
+
focusPosition:5,
|
|
605
|
+
//首次滚动的位置, 可以不传
|
|
606
|
+
scrollToPosition:3,
|
|
607
|
+
//首次滚动的偏移值, 可以不传
|
|
608
|
+
scrollOffset:200,
|
|
609
|
+
}
|
|
610
|
+
*
|
|
611
|
+
**/
|
|
612
|
+
|
|
613
|
+
if (map == null || map.size() < 1) {
|
|
614
|
+
clearInitFocusPosition();
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
int position = map.containsKey("focusPosition") ? map.getInt("focusPosition") : -1;
|
|
618
|
+
if (position < 0) {
|
|
619
|
+
position = map.containsKey("position") ? map.getInt("position") : -1;
|
|
620
|
+
}
|
|
621
|
+
final int scrollToPosition = map.containsKey("scrollToPosition") ? map.getInt("scrollToPosition") : -1;
|
|
622
|
+
final int scrollOffset = map.containsKey("scrollOffset") ? map.getInt("scrollOffset") : 0;
|
|
623
|
+
|
|
624
|
+
final String target = map.containsKey("target") ? map.getString("target") : null;
|
|
625
|
+
// final boolean oneShot = map.getBoolean("oneShot");
|
|
626
|
+
final boolean block = map.containsKey("blockOthers") && map.getBoolean("blockOthers");
|
|
627
|
+
final boolean force = map.containsKey("force") && map.getBoolean("force");
|
|
628
|
+
final int delay = map.containsKey("delay") ? map.getInt("delay") : -1;
|
|
629
|
+
if (position < 0 && scrollToPosition < 0) {
|
|
630
|
+
this.clearInitFocusPosition();
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
boolean requestFocus = position > -1;
|
|
635
|
+
if (LogUtils.isDebug()) {
|
|
636
|
+
Log.d("PendingFocus", "begin initPosition requestFocus:" + requestFocus);
|
|
637
|
+
}
|
|
638
|
+
if (requestFocus) {
|
|
639
|
+
final View targetView = getSingleLineLayoutManager().findTargetChildFocus(position, target);
|
|
640
|
+
if (LogUtils.isDebug()) {
|
|
641
|
+
Log.d("PendingFocus", "findTargetChildFocus findTargetChildFocus:" + targetView);
|
|
642
|
+
}
|
|
643
|
+
if (targetView != null && targetView.getVisibility() == View.VISIBLE) {
|
|
644
|
+
// requestTargetFocus(block,delay,position,target);
|
|
645
|
+
setupInitScrollWork(position, scrollToPosition, scrollOffset, target, block, delay);
|
|
646
|
+
if (force) {
|
|
647
|
+
hideAWhile(300);
|
|
648
|
+
setListData();
|
|
649
|
+
}
|
|
650
|
+
} else {
|
|
651
|
+
setupInitScrollWork(position, scrollToPosition, scrollOffset, target, block, delay);
|
|
652
|
+
if (force) {
|
|
653
|
+
hideAWhile(300);
|
|
654
|
+
setListData();
|
|
655
|
+
}
|
|
656
|
+
if (scrollToPosition > -1) {
|
|
657
|
+
if (LogUtils.isDebug()) {
|
|
658
|
+
Log.e("PendingFocus", "scrollToPositionWithScrollType Directly");
|
|
659
|
+
}
|
|
660
|
+
// scrollToPositionWithScrollType(scrollToPosition,scrollOffset);
|
|
661
|
+
} else {
|
|
662
|
+
// scrollToPositionWithScrollType(position,scrollOffset);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
} else {
|
|
666
|
+
setupInitScrollWork(-1, scrollToPosition, scrollOffset, target, block, delay);
|
|
667
|
+
if (LogUtils.isDebug()) {
|
|
668
|
+
Log.e("PendingFocus", "scrollToPositionWithScrollType Directly!! scrollToPosition:" + scrollToPosition + ",offset:" + scrollOffset + ",id:" + getId());
|
|
669
|
+
}
|
|
670
|
+
if (force) {
|
|
671
|
+
hideAWhile(300);
|
|
672
|
+
setListData();
|
|
673
|
+
}
|
|
674
|
+
// scrollToPositionWithScrollType(scrollToPosition,scrollOffset);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
private Runnable hideTask;
|
|
681
|
+
|
|
682
|
+
private void hideAWhile(int time) {
|
|
683
|
+
//暂时将自己隐藏一会,主要用来解决列表重设数据,多次变更的问题
|
|
684
|
+
if (hideTask != null) {
|
|
685
|
+
removeCallbacks(hideTask);
|
|
686
|
+
}
|
|
687
|
+
setAlpha(0);
|
|
688
|
+
hideTask = () -> setAlpha(1);
|
|
689
|
+
postDelayed(hideTask, time);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
@Override
|
|
694
|
+
protected void scrollToPositionBeforeSetListData() {
|
|
695
|
+
super.scrollToPositionBeforeSetListData();
|
|
696
|
+
|
|
697
|
+
int position = getScrollToPosition();
|
|
698
|
+
int itemHeight;
|
|
699
|
+
int offset = 0;
|
|
700
|
+
if (getListAdapter() == null) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
itemHeight = getListAdapter().getItemHeight(position);
|
|
705
|
+
|
|
706
|
+
int parentSize = getHeight() - getPaddingBottom() - getPaddingTop();
|
|
707
|
+
|
|
708
|
+
final int lastIndex = getListAdapter().getItemCount() - 1;
|
|
709
|
+
if (getSingleLineLayoutManager().childOnScreenScroller.type == TVRecyclerView.REQUEST_CHILD_ON_SCREEN_TYPE_CENTER) {
|
|
710
|
+
offset = (int) ((parentSize - itemHeight) * 0.5f);
|
|
711
|
+
}
|
|
712
|
+
if (mInitParams != null) {
|
|
713
|
+
offset += mInitParams.scrollOffset;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
Log.i(TAG, "scrollToPositionBeforeSetListData parentSize:" + parentSize + ",itemHeight:" + itemHeight + ",offset:" + offset);
|
|
717
|
+
//设置的offset超过边界,跳转到最后一个Item上去
|
|
718
|
+
if (position >= lastIndex) {
|
|
719
|
+
position = lastIndex;
|
|
720
|
+
//不能划出内容高度
|
|
721
|
+
if (offset < 0) {
|
|
722
|
+
offset = 0;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (position > -1) {
|
|
726
|
+
scrollToPosition(position, offset);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
public void scrollToPositionWithScrollType(int position, int offset) {
|
|
731
|
+
Log.e("PendingFocus", "scrollToPositionWithScrollType position:" + position + ",offset:" + offset);
|
|
732
|
+
scrollToPosition(position, offset);
|
|
733
|
+
// dispatchLayout();
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* 设置选中的子view,注意此方法只在view已经显示出来以后调用才有效。
|
|
739
|
+
*
|
|
740
|
+
* @param position
|
|
741
|
+
*/
|
|
742
|
+
public void setTargetChildPosition(int position) {
|
|
743
|
+
this.setSelectChildPosition(position, true);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* 设置选中的子view,注意此方法只在view已经显示出来以后调用才有效。
|
|
748
|
+
*
|
|
749
|
+
* @param position
|
|
750
|
+
*/
|
|
751
|
+
public void setSelectChildPosition(int position, boolean changeTargetFocusChild) {
|
|
752
|
+
Log.d(TAG, "setSelectChildPosition position:" + position + " ,changeTargetFocusChild:" + changeTargetFocusChild);
|
|
753
|
+
final View selectedChild = findSelectedChild();
|
|
754
|
+
if (selectedChild != null && selectedChild.isSelected()) {
|
|
755
|
+
selectedChild.setSelected(false);
|
|
756
|
+
}
|
|
757
|
+
if (changeTargetFocusChild) {
|
|
758
|
+
setTargetFocusChildPosition(position);
|
|
759
|
+
}
|
|
760
|
+
this.defaultSectionPosition = position;
|
|
761
|
+
if (!hasFocus() || !enableSelectOnFocus) {
|
|
762
|
+
final View next = findViewByPosition(position);
|
|
763
|
+
changeSelectState(next, true);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
private int layoutTriggerTargetPosition = -1;
|
|
768
|
+
|
|
769
|
+
public void setLayoutTriggerTargetPosition(int position) {
|
|
770
|
+
this.layoutTriggerTargetPosition = position;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
public void setScrollOffset(int mScrollOffset) {
|
|
775
|
+
this.mScrollOffset = mScrollOffset;
|
|
776
|
+
if (singleLineLayoutManager != null) {
|
|
777
|
+
singleLineLayoutManager.childOnScreenScroller.setScrollOffset(mScrollOffset);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
@Override
|
|
783
|
+
protected LinearLayoutManager onCreateLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
|
784
|
+
singleLineLayoutManager = new SingleLineLayoutManager(this, orientation);
|
|
785
|
+
singleLineLayoutManager.setFocusEventListener(mFocusListener);
|
|
786
|
+
//onAddDefaultItemDecoration();
|
|
787
|
+
return singleLineLayoutManager;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
protected boolean isSelectedChildValid(View child) {
|
|
792
|
+
boolean b = child != null;
|
|
793
|
+
if (b) {
|
|
794
|
+
b &= child.getVisibility() == View.VISIBLE;
|
|
795
|
+
if (DEBUG) {
|
|
796
|
+
Log.d(TAG, "isSelectedChildValid Visibility():" + b);
|
|
797
|
+
}
|
|
798
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
799
|
+
b &= child.isAttachedToWindow();
|
|
800
|
+
if (DEBUG) {
|
|
801
|
+
Log.d(TAG, "isSelectedChildValid isAttachedToWindow:" + b);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
b &= TVViewUtil.isViewDescendantOf(child, this);
|
|
805
|
+
if (DEBUG) {
|
|
806
|
+
Log.d(TAG, "isSelectedChildValid isViewDescendantOf:" + b);
|
|
807
|
+
}
|
|
808
|
+
final int visibility = child.getWindowVisibility();
|
|
809
|
+
if (DEBUG) {
|
|
810
|
+
Log.d(TAG, "isSelectedChildValid child visibility:" + visibility);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return b;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
protected void onAddDefaultItemDecoration() {
|
|
817
|
+
addItemDecoration(new ItemDecorations.ListEndBlank(orientation));
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
public SingleLineLayoutManager getSingleLineLayoutManager() {
|
|
821
|
+
return singleLineLayoutManager;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
private ArrayList mTempList;
|
|
826
|
+
|
|
827
|
+
@Override
|
|
828
|
+
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
|
|
829
|
+
LogUtils.d(FocusDispatchView.TAG, "addFocusables start inTVRecyclerView " + ",childCount:" + getChildCount());
|
|
830
|
+
if (mFocusSearchTargets != null) {
|
|
831
|
+
for (View v : mFocusSearchTargets) {
|
|
832
|
+
v.addFocusables(views, direction, focusableMode);
|
|
833
|
+
}
|
|
834
|
+
if (LogUtils.isDebug()) {
|
|
835
|
+
LogUtils.d("SingleLineRecyclerView", "addFocusables In Target:" + mFocusSearchTargets + " views size:" + views.size());
|
|
836
|
+
}
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (!hasFocus() && enableFocusMemory) {
|
|
841
|
+
|
|
842
|
+
View target = null;
|
|
843
|
+
if (mTargetFocusChildPosition > -1) {
|
|
844
|
+
target = getSingleLineLayoutManager().findViewByPosition(mTargetFocusChildPosition);
|
|
845
|
+
}
|
|
846
|
+
if (!isSelectedChildValid(target)) {
|
|
847
|
+
target = null;
|
|
848
|
+
}
|
|
849
|
+
if (target != null) {
|
|
850
|
+
//没有View被选中
|
|
851
|
+
target.addFocusables(views, direction, focusableMode);
|
|
852
|
+
if (LogUtils.isDebug()) {
|
|
853
|
+
Log.d("SingleLineRecyclerView", "addFocusables on mTargetFocusChildPosition:" + mTargetFocusChildPosition);
|
|
854
|
+
}
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
View mSelectedChild = findSelectedChild();
|
|
859
|
+
|
|
860
|
+
if (!isSelectedChildValid(findSelectedChild())) {
|
|
861
|
+
mSelectedChild = null;
|
|
862
|
+
}
|
|
863
|
+
final int childCount = getChildCount();
|
|
864
|
+
if (childCount > 0) {
|
|
865
|
+
if (mSelectedChild == null) {
|
|
866
|
+
//没有View被选中
|
|
867
|
+
final View v = getChildAt(0);
|
|
868
|
+
if (v != null && v.getVisibility() == View.VISIBLE) {
|
|
869
|
+
if (LogUtils.isDebug()) {
|
|
870
|
+
Log.d("SingleLineRecyclerView", "没有过焦点的列表,焦点给第一个view:" + v);
|
|
871
|
+
}
|
|
872
|
+
if (mTempList == null) {
|
|
873
|
+
mTempList = new ArrayList();
|
|
874
|
+
} else {
|
|
875
|
+
mTempList.clear();
|
|
876
|
+
}
|
|
877
|
+
v.addFocusables(mTempList, direction, focusableMode);
|
|
878
|
+
if (mTempList.size() > 0) {
|
|
879
|
+
views.addAll(mTempList);
|
|
880
|
+
} else {
|
|
881
|
+
if (LogUtils.isDebug()) {
|
|
882
|
+
Log.e(TAG, "RecyclerView add addFocusables empty,call super.addFocusables(), first child:" + v);
|
|
883
|
+
}
|
|
884
|
+
super.addFocusables(views, direction, focusableMode);
|
|
885
|
+
}
|
|
886
|
+
mTempList.clear();
|
|
887
|
+
} else {
|
|
888
|
+
super.addFocusables(views, direction, focusableMode);
|
|
889
|
+
}
|
|
890
|
+
} else {
|
|
891
|
+
if (LogUtils.isDebug()) {
|
|
892
|
+
Log.d("SingleLineRecyclerView", "有过焦点的列表,焦点给曾经有过焦点的View:mLastFocusedChild:");
|
|
893
|
+
}
|
|
894
|
+
mSelectedChild.addFocusables(views, direction, focusableMode);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
} else {
|
|
898
|
+
super.addFocusables(views, direction, focusableMode);
|
|
899
|
+
if (LogUtils.isDebug()) {
|
|
900
|
+
LogUtils.d("SingleLineRecyclerView", "addFocusables by super views size:" + views.size());
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (LogUtils.isDebug()) {
|
|
904
|
+
LogUtils.d(FocusDispatchView.TAG, "addFocusables end inTVRecyclerView " + ",resultCount:" + views.size());
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
@Override
|
|
910
|
+
protected void onDetachedFromWindow() {
|
|
911
|
+
if (LogUtils.isDebug()) {
|
|
912
|
+
Log.d("SingleLineRecyclerView", "onDetachedFromWindow");
|
|
913
|
+
}
|
|
914
|
+
super.onDetachedFromWindow();
|
|
915
|
+
stopListenGlobalFocusChange();
|
|
916
|
+
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
public void setFocusEventListener(FocusEventListener mFocusListener) {
|
|
921
|
+
this.mFocusListener = mFocusListener;
|
|
922
|
+
if (singleLineLayoutManager != null) {
|
|
923
|
+
singleLineLayoutManager.setFocusEventListener(mFocusListener);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
@Override
|
|
931
|
+
protected void dispatchDraw(Canvas canvas) {
|
|
932
|
+
if (singleLineLayoutManager.isInReFocus()) {
|
|
933
|
+
// Log.e("zhaopeng","dispatchDraw inReFocus return!!");
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
super.dispatchDraw(canvas);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
@Override
|
|
940
|
+
public void draw(Canvas c) {
|
|
941
|
+
if (singleLineLayoutManager.isInReFocus()) {
|
|
942
|
+
// Log.e("zhaopeng","draw inReFocus return!!");
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
super.draw(c);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
void requestFocusSearchInChild(View[] targets, View focused, int direction) {
|
|
949
|
+
mFocusSearchTargets = targets;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
void removeSearchInChildRequest() {
|
|
953
|
+
this.mFocusSearchTargets = null;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
View searchInTargets(View[] targets, View focused, int direction) {
|
|
957
|
+
requestFocusSearchInChild(targets, focused, direction);
|
|
958
|
+
View result = null;
|
|
959
|
+
try {
|
|
960
|
+
//这里需要从瀑布流内部寻找,不能只在组件内寻找,否则焦点只能在第一个位置出现
|
|
961
|
+
result = FocusFinder.getInstance().findNextFocus(this, focused, direction);
|
|
962
|
+
} catch (Throwable t) {
|
|
963
|
+
result = null;
|
|
964
|
+
}
|
|
965
|
+
removeSearchInChildRequest();
|
|
966
|
+
return result;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
@Override
|
|
970
|
+
public View focusSearch(View focused, int direction) {
|
|
971
|
+
View v = super.focusSearch(focused, direction);
|
|
972
|
+
// if (v != null) {
|
|
973
|
+
// currentFocusView = v;
|
|
974
|
+
// }
|
|
975
|
+
//wanglei add : ul添加焦点抖动
|
|
976
|
+
if ((focused == v || v == null) && listShakeSelf) {
|
|
977
|
+
singleLineLayoutManager.shakeSelf(focused, direction);
|
|
978
|
+
}
|
|
979
|
+
//修改触底回弹为焦点抖动
|
|
980
|
+
singleLineLayoutManager.shakeEndIfNeed(focused, v, direction);
|
|
981
|
+
return v;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
@Override
|
|
985
|
+
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
986
|
+
return super.dispatchKeyEvent(event);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
public static class FocusEventListener {
|
|
990
|
+
|
|
991
|
+
public View onFocusSearchFailedAtEnd(@NonNull View focused, int direction) {
|
|
992
|
+
return focused;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
public View onInterceptFocusSearch(@NonNull View focused, int direction) {
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
public View onFocusSearchFailed(View focused, int focusDirection, Recycler recycler, State state) {
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
protected View onFocusSearchFailedAtEnd(@NonNull View focused, int direction) {
|
|
1006
|
+
return null;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
@Override
|
|
1011
|
+
public void smoothScrollBy(int dx, int dy, boolean careSpringBackMaxDistance, boolean forceScroll) {
|
|
1012
|
+
super.smoothScrollBy(dx, dy, careSpringBackMaxDistance, forceScroll);
|
|
1013
|
+
if(LogUtils.isDebug()) {
|
|
1014
|
+
Log.i(AutoFocusManager.TAG, " ul smoothScrollBy dx:" + dx + ",dy:" + dy + ",hasFocus:" + hasFocus() + ",initFocusPositionAfterLayout" + initFocusPositionAfterLayout);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
private class CenterSmoothScroller extends LinearSmoothScroller {
|
|
1020
|
+
|
|
1021
|
+
public CenterSmoothScroller(Context context) {
|
|
1022
|
+
super(context);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
@Override
|
|
1026
|
+
public PointF computeScrollVectorForPosition(int targetPosition) {
|
|
1027
|
+
return getSingleLineLayoutManager().computeScrollVectorForPosition(targetPosition);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
@Override
|
|
1031
|
+
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
|
|
1032
|
+
return super.calculateDtToFit(viewStart, viewEnd, boxStart, boxEnd, snapPreference);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
int shakePreCheckNumber = 2;
|
|
1037
|
+
|
|
1038
|
+
public void setShakePreCheckNumber(int shakePreCheckNumber) {
|
|
1039
|
+
this.shakePreCheckNumber = shakePreCheckNumber;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
public static class SingleLineLayoutManager extends LinearLayoutManager {
|
|
1044
|
+
|
|
1045
|
+
private final int orientation;
|
|
1046
|
+
|
|
1047
|
+
final ChildOnScreenScroller.Default childOnScreenScroller;
|
|
1048
|
+
private FocusEventListener mFocusListener;
|
|
1049
|
+
private final TVRecyclerView mRecyclerView;
|
|
1050
|
+
private int mCurrentDirection = -1;
|
|
1051
|
+
private ReFocus mReFocus;
|
|
1052
|
+
|
|
1053
|
+
@Override
|
|
1054
|
+
public boolean requestChildRectangleOnScreen(RecyclerViewBase parent, View child, Rect rect, boolean immediate) {
|
|
1055
|
+
final ChildOnScreenScroller scroller = mRecyclerView.mCustomChildOnScreenScroller != null ? mRecyclerView.mCustomChildOnScreenScroller : childOnScreenScroller;
|
|
1056
|
+
if (scroller != null && scroller.requestChildRectangleOnScreen(parent, child, rect, immediate, mCurrentDirection)) {
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
return super.requestChildRectangleOnScreen(parent, child, rect, immediate);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
@Override
|
|
1064
|
+
public void smoothScrollToPosition(RecyclerViewBase recyclerView, State state, int position) {
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
final ChildOnScreenScroller scroller = mRecyclerView.mCustomChildOnScreenScroller != null ? mRecyclerView.mCustomChildOnScreenScroller : childOnScreenScroller;
|
|
1068
|
+
if (scroller != null && scroller.smoothScrollToPosition(recyclerView, state, position)) {
|
|
1069
|
+
} else {
|
|
1070
|
+
super.smoothScrollToPosition(recyclerView, state, position);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
public SingleLineLayoutManager(final TVRecyclerView mRecyclerView, int orientation) {
|
|
1076
|
+
super(mRecyclerView.getContext(), orientation, false);
|
|
1077
|
+
this.mRecyclerView = mRecyclerView;
|
|
1078
|
+
childOnScreenScroller = new ChildOnScreenScroller.Default(orientation);
|
|
1079
|
+
childOnScreenScroller.setScrollOffset(mRecyclerView.mScrollOffset);
|
|
1080
|
+
this.orientation = orientation;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
boolean isInReFocus() {
|
|
1084
|
+
// return mReFocus != null && mReFocus.inReFocus;
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
public void setFocusEventListener(FocusEventListener mFocusListener) {
|
|
1089
|
+
this.mFocusListener = mFocusListener;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
@Override
|
|
1094
|
+
public void onAdapterChanged(@Nullable Adapter oldAdapter, @Nullable Adapter newAdapter) {
|
|
1095
|
+
super.onAdapterChanged(oldAdapter, newAdapter);
|
|
1096
|
+
mRecyclerView.defaultSectionPosition = -1;
|
|
1097
|
+
mRecyclerView.resetScrollY();
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
@Override
|
|
1102
|
+
public void scrollToPosition(int position) {
|
|
1103
|
+
super.scrollToPosition(position);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
@Override
|
|
1108
|
+
public boolean onRequestChildFocus(RecyclerViewBase parent, View child, View focused) {
|
|
1109
|
+
return super.onRequestChildFocus(parent, child, focused);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
private HippyViewEvent mFocusSearchFailEvent;
|
|
1114
|
+
|
|
1115
|
+
private HippyViewEvent getFocusSearchFailEvent() {
|
|
1116
|
+
if (mFocusSearchFailEvent == null) {
|
|
1117
|
+
mFocusSearchFailEvent = new HippyViewEvent(InternalExtendViewUtil.LIST_FOCUS_SEARCH_FAIL_EVENT_NAME);
|
|
1118
|
+
}
|
|
1119
|
+
return mFocusSearchFailEvent;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
private void eatReFocus() {
|
|
1123
|
+
mReFocus = null;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
@Override
|
|
1127
|
+
public void handleFocusBeforeLayout(Recycler recycler, State state, boolean dataChanged) {
|
|
1128
|
+
if (LogUtils.isDebug()) {
|
|
1129
|
+
LogUtils.d("ReFocus", "+++handleFocusBeforeLayout state:" + state + " ,hasFocus:" + hasFocus() + ",dataChanged: " + dataChanged + ",id:" + mRecyclerView.getId());
|
|
1130
|
+
}
|
|
1131
|
+
boolean forPendingWork = mRecyclerView.mInitParams != null && mRecyclerView.mInitParams.targetFocusPosition > -1;
|
|
1132
|
+
if (forPendingWork) {
|
|
1133
|
+
if (LogUtils.isDebug()) {
|
|
1134
|
+
LogUtils.d("ReFocus", "+++handleFocusBeforeLayout forPendingWork ignore ReFocus");
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (dataChanged) {
|
|
1139
|
+
//zhaopeng 如果数据没有改变而记住焦点,会造成scrollToIndex时无法回收导致的绘制残留
|
|
1140
|
+
if (mRecyclerView.initFocusPositionAfterLayout > -1) {
|
|
1141
|
+
if (LogUtils.isDebug()) {
|
|
1142
|
+
LogUtils.d("ReFocus", "handleFocusBeforeLayout initFocusPositionAfterLayout:" + mRecyclerView.initFocusPositionAfterLayout);
|
|
1143
|
+
}
|
|
1144
|
+
mReFocus = new ReFocus(mRecyclerView.initFocusPositionAfterLayout, null, null);
|
|
1145
|
+
mRecyclerView.initFocusPositionAfterLayout = -1;
|
|
1146
|
+
} else {
|
|
1147
|
+
final View child = mRecyclerView.getFocusedChild();
|
|
1148
|
+
if (hasFocus() && child != null) {
|
|
1149
|
+
final View focused = child.findFocus();
|
|
1150
|
+
final int oldPos = getPosition(mRecyclerView.getFocusedChild());
|
|
1151
|
+
InternalExtendViewUtil.blockRootFocus(mRecyclerView);
|
|
1152
|
+
mReFocus = new ReFocus(oldPos, focused, child);
|
|
1153
|
+
if (LogUtils.isDebug()) {
|
|
1154
|
+
LogUtils.d("ReFocus", "+++handleFocusBeforeLayout mReFocus:" + mReFocus);
|
|
1155
|
+
}
|
|
1156
|
+
} else {
|
|
1157
|
+
mReFocus = null;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (LogUtils.isDebug()) {
|
|
1162
|
+
Log.d(FocusDispatchView.TAG, "+++++handleFocusBeforeLayout mReFocus:" + mReFocus);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
boolean requestTargetChildFocus(int position, String name) {
|
|
1167
|
+
final View targetChild = findViewByPosition(position);
|
|
1168
|
+
boolean b = false;
|
|
1169
|
+
final int itemCount = getItemCount();
|
|
1170
|
+
final int lastVisible = findLastVisibleItemPosition();
|
|
1171
|
+
if (name == null) {
|
|
1172
|
+
if (targetChild instanceof RecyclerViewItem && targetChild.getVisibility() == View.VISIBLE) {
|
|
1173
|
+
((RecyclerViewItem) targetChild).requestContentFocus();
|
|
1174
|
+
b = true;
|
|
1175
|
+
if (LogUtils.isDebug()) {
|
|
1176
|
+
Log.e("PendingFocus", "requestTargetChildFocus targetChild:" + targetChild + ",pos:" + position + ",itemCount:" + itemCount + ",lastVisible:" + lastVisible + ",id:" + mRecyclerView.getId());
|
|
1177
|
+
}
|
|
1178
|
+
} else if (targetChild != null && targetChild.getVisibility() == View.VISIBLE) {
|
|
1179
|
+
if (LogUtils.isDebug()) {
|
|
1180
|
+
Log.e("PendingFocus", "requestTargetChildFocus targetChild:" + targetChild + ",pos:" + position + ",itemCount:" + itemCount + ",lastVisible:" + lastVisible + ",id:" + mRecyclerView.getId());
|
|
1181
|
+
}
|
|
1182
|
+
targetChild.requestFocus();
|
|
1183
|
+
b = true;
|
|
1184
|
+
}
|
|
1185
|
+
} else {
|
|
1186
|
+
View view = ControllerManager.findViewByName(mRecyclerView, name);
|
|
1187
|
+
if (view != null && view.getVisibility() == View.VISIBLE) {
|
|
1188
|
+
view.requestFocus();
|
|
1189
|
+
b = true;
|
|
1190
|
+
} else {
|
|
1191
|
+
if (LogUtils.isDebug()) {
|
|
1192
|
+
Log.e("PendingFocus", "requestTargetChildFocus error: targetView is null");
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return b;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
View findTargetChildFocus(int position, String name) {
|
|
1200
|
+
final View targetChild = findViewByPosition(position);
|
|
1201
|
+
|
|
1202
|
+
View result;
|
|
1203
|
+
if (name == null) {
|
|
1204
|
+
if (targetChild instanceof RecyclerViewItem) {
|
|
1205
|
+
result = ((RecyclerViewItem) targetChild).getContentView();
|
|
1206
|
+
} else {
|
|
1207
|
+
if (LogUtils.isDebug()) {
|
|
1208
|
+
Log.e("PendingFocus", "requestTargetChildFocus targetChild:" + targetChild);
|
|
1209
|
+
}
|
|
1210
|
+
result = targetChild;
|
|
1211
|
+
}
|
|
1212
|
+
} else {
|
|
1213
|
+
result = ControllerManager.findViewByName(mRecyclerView, name);
|
|
1214
|
+
}
|
|
1215
|
+
return result;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
void consumePendingWork() {
|
|
1220
|
+
final InitParams pf = mRecyclerView.mInitParams;
|
|
1221
|
+
final View targetChild = findViewByPosition(pf.targetFocusPosition);
|
|
1222
|
+
if (targetChild != null) {
|
|
1223
|
+
if (LogUtils.isDebug()) {
|
|
1224
|
+
LogUtils.d("PendingFocus", "handleFocusAfterLayout targetChild:" + targetChild + ",PendingFocus:" + pf);
|
|
1225
|
+
}
|
|
1226
|
+
//child 已经显示出来
|
|
1227
|
+
if (pf.blockOthers) {
|
|
1228
|
+
if (LogUtils.isDebug()) {
|
|
1229
|
+
Log.e("PendingFocus", "handleFocusAfterLayout PendingFocus unBlockRootFocus");
|
|
1230
|
+
}
|
|
1231
|
+
if (LogUtils.isDebug()) {
|
|
1232
|
+
LogUtils.e(FocusDispatchView.TAG, "unBlockRootFocus 3");
|
|
1233
|
+
}
|
|
1234
|
+
InternalExtendViewUtil.unBlockRootFocus(mRecyclerView);
|
|
1235
|
+
}
|
|
1236
|
+
boolean b;
|
|
1237
|
+
callNotifyInReFocus(targetChild, true);
|
|
1238
|
+
if (pf.delay > 0) {
|
|
1239
|
+
mRecyclerView.getRootView().postDelayed(new Runnable() {
|
|
1240
|
+
@Override
|
|
1241
|
+
public void run() {
|
|
1242
|
+
final boolean requested = requestTargetChildFocus(pf.targetFocusPosition, null);
|
|
1243
|
+
if (requested) {
|
|
1244
|
+
mRecyclerView.clearInitFocusPosition();
|
|
1245
|
+
if (LogUtils.isDebug()) {
|
|
1246
|
+
Log.e("PendingFocus", "handleFocusAfterLayout PendingFocus one-shot clear");
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
callNotifyInReFocus(targetChild, false);
|
|
1250
|
+
}
|
|
1251
|
+
}, pf.delay);
|
|
1252
|
+
} else {
|
|
1253
|
+
b = requestTargetChildFocus(pf.targetFocusPosition, pf.targetName);
|
|
1254
|
+
callNotifyInReFocus(targetChild, false);
|
|
1255
|
+
|
|
1256
|
+
if (b) {
|
|
1257
|
+
mRecyclerView.clearInitFocusPosition();
|
|
1258
|
+
if (LogUtils.isDebug()) {
|
|
1259
|
+
Log.e("PendingFocus", "handleFocusAfterLayout PendingFocus one-shot clear");
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
@Override
|
|
1268
|
+
public void handleFocusAfterLayout(Recycler recycler, State state, boolean dataChanged) {
|
|
1269
|
+
if (LogUtils.isDebug()) {
|
|
1270
|
+
LogUtils.d("ReFocus", "---handleFocusAfterLayout state:" + state + " ,hasFocus:" + hasFocus() + ",dataChanged:" + dataChanged + "mReFocus:" + mReFocus + ",id:" + mRecyclerView.getId());
|
|
1271
|
+
}
|
|
1272
|
+
if (LogUtils.isDebug()) {
|
|
1273
|
+
Log.e(FocusDispatchView.TAG, "-----handleFocusAfterLayout mReFocus:" + mReFocus);
|
|
1274
|
+
}
|
|
1275
|
+
doReFocus(dataChanged);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
void doReFocus(boolean dataChanged) {
|
|
1279
|
+
if (mRecyclerView.mInitParams != null && mRecyclerView.mInitParams.targetFocusPosition > -1) {
|
|
1280
|
+
consumePendingWork();
|
|
1281
|
+
} else {
|
|
1282
|
+
if (mReFocus != null && mReFocus.valid && !isInReFocus() && dataChanged) {
|
|
1283
|
+
//1. 尝试找到上次
|
|
1284
|
+
mReFocus.inReFocus = true;
|
|
1285
|
+
|
|
1286
|
+
final int oldPos = mReFocus.oldPosition;
|
|
1287
|
+
|
|
1288
|
+
final View f = findViewByPosition(oldPos);
|
|
1289
|
+
if (f != null && !f.isFocused()) {
|
|
1290
|
+
|
|
1291
|
+
|
|
1292
|
+
final View oldFocused = mReFocus.oldFocus;
|
|
1293
|
+
View target = f;
|
|
1294
|
+
|
|
1295
|
+
if (f instanceof ViewGroup) {
|
|
1296
|
+
if (TVViewUtil.isViewDescendantOf(oldFocused, (ViewGroup) f) && oldFocused != f) {
|
|
1297
|
+
if (LogUtils.isDebug()) {
|
|
1298
|
+
LogUtils.d("ReFocus", "focus isViewDescendantOf child true");
|
|
1299
|
+
}
|
|
1300
|
+
target = oldFocused;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
InternalExtendViewUtil.unBlockRootFocus(mRecyclerView);
|
|
1304
|
+
if (target != null) {
|
|
1305
|
+
if (LogUtils.isDebug()) {
|
|
1306
|
+
LogUtils.e(FocusDispatchView.TAG, "unBlockRootFocus 4");
|
|
1307
|
+
}
|
|
1308
|
+
callNotifyInReFocus(f, true);
|
|
1309
|
+
target.requestFocus();
|
|
1310
|
+
callNotifyInReFocus(f, false);
|
|
1311
|
+
} else {
|
|
1312
|
+
if (LogUtils.isDebug()) {
|
|
1313
|
+
LogUtils.e(FocusDispatchView.TAG, "postReFocus 4");
|
|
1314
|
+
}
|
|
1315
|
+
// postReFocus();
|
|
1316
|
+
}
|
|
1317
|
+
if (LogUtils.isDebug()) {
|
|
1318
|
+
LogUtils.d("ReFocus", "---handleFocusAfterLayout exeRequestFocus oldFocusPos:" + oldPos + " target:" + target);
|
|
1319
|
+
LogUtils.d("PendingFocus", "---handleFocusAfterLayout exeRequestFocus oldFocusPos:" + oldPos + " target:" + target);
|
|
1320
|
+
}
|
|
1321
|
+
} else {
|
|
1322
|
+
if (LogUtils.isDebug()) {
|
|
1323
|
+
LogUtils.d("ReFocus", "cant find oldFocus unBlockFocus");
|
|
1324
|
+
LogUtils.e(FocusDispatchView.TAG, "unBlockRootFocus 5 ");
|
|
1325
|
+
}
|
|
1326
|
+
if (mReFocus != null && mReFocus.valid) {
|
|
1327
|
+
if (LogUtils.isDebug()) {
|
|
1328
|
+
Log.d(FocusDispatchView.TAG, "postReFocus 5," + mReFocus);
|
|
1329
|
+
}
|
|
1330
|
+
// postReFocus();
|
|
1331
|
+
InternalExtendViewUtil.unBlockRootFocus(mRecyclerView);
|
|
1332
|
+
} else {
|
|
1333
|
+
InternalExtendViewUtil.unBlockRootFocus(mRecyclerView);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
eatReFocus();
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
Runnable reFocusTask;
|
|
1343
|
+
|
|
1344
|
+
void postReFocus() {
|
|
1345
|
+
|
|
1346
|
+
if (mRecyclerView != null) {
|
|
1347
|
+
mRecyclerView.removeCallbacks(reFocusTask);
|
|
1348
|
+
}
|
|
1349
|
+
reFocusTask = new Runnable() {
|
|
1350
|
+
@Override
|
|
1351
|
+
public void run() {
|
|
1352
|
+
if (LogUtils.isDebug()) {
|
|
1353
|
+
Log.e(FocusDispatchView.TAG, "exe doReFocus on postReFocus !!! Refoucs:" + mReFocus);
|
|
1354
|
+
}
|
|
1355
|
+
doReFocus(true);
|
|
1356
|
+
eatReFocus();
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
mRecyclerView.postDelayed(reFocusTask, 100);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
void callNotifyInReFocus(View child, boolean inFocus) {
|
|
1363
|
+
if (child instanceof ITVView) {
|
|
1364
|
+
((ITVView) child).notifyInReFocus(inFocus);
|
|
1365
|
+
} else if (child instanceof RecyclerViewItem) {
|
|
1366
|
+
((RecyclerViewItem) child).notifyInReFocus(inFocus);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
private int getVectorByDirection(int direction) {
|
|
1371
|
+
int vector = 0;
|
|
1372
|
+
boolean vertical = orientation == RecyclerViewBase.VERTICAL;
|
|
1373
|
+
if (vertical) {
|
|
1374
|
+
if (direction == FOCUS_UP) {
|
|
1375
|
+
vector = -1;
|
|
1376
|
+
} else if (direction == FOCUS_DOWN) {
|
|
1377
|
+
vector = 1;
|
|
1378
|
+
}
|
|
1379
|
+
} else {
|
|
1380
|
+
if (direction == FOCUS_LEFT) {
|
|
1381
|
+
vector = -1;
|
|
1382
|
+
} else if (direction == FOCUS_RIGHT) {
|
|
1383
|
+
vector = 1;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
return vector;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// @Nullable
|
|
1390
|
+
@Override
|
|
1391
|
+
public View onInterceptFocusSearch(@NonNull View focused, int direction) {
|
|
1392
|
+
mCurrentDirection = direction;
|
|
1393
|
+
if (InternalExtendViewUtil.isContainBlockDirection(direction, mRecyclerView.mBlockFocus)) {
|
|
1394
|
+
LogUtils.e(FocusDispatchView.TAG, "onInterceptFocusSearch ul: containBlockDirection is true return focused ,direction:" + direction);
|
|
1395
|
+
return focused;
|
|
1396
|
+
}
|
|
1397
|
+
if (!mRecyclerView.useAdvancedFocusSearch) {
|
|
1398
|
+
return super.onInterceptFocusSearch(focused, direction);
|
|
1399
|
+
}
|
|
1400
|
+
View result = null;
|
|
1401
|
+
if (mFocusListener != null) {
|
|
1402
|
+
result = mFocusListener.onInterceptFocusSearch(focused, direction);
|
|
1403
|
+
}
|
|
1404
|
+
if (result == null) {
|
|
1405
|
+
int vector = getVectorByDirection(direction);
|
|
1406
|
+
final int focusPosition = mRecyclerView.mFocusChildPosition;
|
|
1407
|
+
|
|
1408
|
+
if (result == null && vector != 0) {
|
|
1409
|
+
int targetPosition = focusPosition + vector;
|
|
1410
|
+
final int itemCount = getItemCount();
|
|
1411
|
+
if (focusPosition > -1 && focusPosition < itemCount - 1) {
|
|
1412
|
+
View current = findViewByPosition(focusPosition);
|
|
1413
|
+
View next = findViewByPosition(targetPosition);
|
|
1414
|
+
if (current != null) {
|
|
1415
|
+
View[] targets = new View[next == null ? 1 : 2];
|
|
1416
|
+
targets[0] = current;
|
|
1417
|
+
if (next != null) {
|
|
1418
|
+
targets[1] = next;
|
|
1419
|
+
}
|
|
1420
|
+
result = mRecyclerView.searchInTargets(targets, focused, direction);
|
|
1421
|
+
LogUtils.d(FocusDispatchView.TAG, "onInterceptFocusSearch result:" + result);
|
|
1422
|
+
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return result;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
@Override
|
|
1431
|
+
protected View findNextFocusAfterFill(View focused, int focusDirection, Recycler recycler, State state) {
|
|
1432
|
+
int vector = getVectorByDirection(focusDirection);
|
|
1433
|
+
final int focusPosition = mRecyclerView.mFocusChildPosition;
|
|
1434
|
+
|
|
1435
|
+
View result = null;
|
|
1436
|
+
if (vector != 0) {
|
|
1437
|
+
int targetPosition = focusPosition + vector;
|
|
1438
|
+
final int itemCount = getItemCount();
|
|
1439
|
+
if (focusPosition > -1 && focusPosition < itemCount - 1) {
|
|
1440
|
+
View current = findViewByPosition(focusPosition);
|
|
1441
|
+
View next = findViewByPosition(targetPosition);
|
|
1442
|
+
if (current != null) {
|
|
1443
|
+
View[] targets = new View[next == null ? 1 : 2];
|
|
1444
|
+
targets[0] = current;
|
|
1445
|
+
if (next != null) {
|
|
1446
|
+
targets[1] = next;
|
|
1447
|
+
}
|
|
1448
|
+
result = mRecyclerView.searchInTargets(targets, focused, focusDirection);
|
|
1449
|
+
LogUtils.d(TAG, "findNextFocusAfterFill result:" + result);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
if (result == null) {
|
|
1454
|
+
LogUtils.e(TAG, "findNextFocusAfterFill return null");
|
|
1455
|
+
return super.findNextFocusAfterFill(focused, focusDirection, recycler, state);
|
|
1456
|
+
} else {
|
|
1457
|
+
return result;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
@Override
|
|
1462
|
+
public View onFocusSearchFailed(View focused, int focusDirection, Recycler recycler, State state) {
|
|
1463
|
+
final View resultFromParent = super.onFocusSearchFailed(focused, focusDirection, recycler, state);
|
|
1464
|
+
|
|
1465
|
+
if(mRecyclerView.mListenFocusSearchOnFail && resultFromParent == null){
|
|
1466
|
+
InternalExtendViewUtil.sendEventOnListFocusSearchFailed(mRecyclerView,mRecyclerView.getFocusedChild(),focused,focusDirection,getFocusSearchFailEvent());
|
|
1467
|
+
if(LogUtils.isDebug()) {
|
|
1468
|
+
LogUtils.e(FocusDispatchView.TAG, "ul: mListenFocusSearchOnFail == true , return focused direction:" + focusDirection);
|
|
1469
|
+
}
|
|
1470
|
+
return focused;
|
|
1471
|
+
}
|
|
1472
|
+
if(InternalExtendViewUtil.isContainBlockDirection(focusDirection,mRecyclerView.mBlockFocusOnFail)){
|
|
1473
|
+
if(resultFromParent == null || mRecyclerView.forceBlockFocusOnFail) {
|
|
1474
|
+
if(LogUtils.isDebug()) {
|
|
1475
|
+
LogUtils.e(FocusDispatchView.TAG, "ul: containBlockDirection is true return focused ,direction:" + focusDirection);
|
|
1476
|
+
}
|
|
1477
|
+
return focused;
|
|
1478
|
+
}else{
|
|
1479
|
+
if(LogUtils.isDebug()) {
|
|
1480
|
+
LogUtils.d(FocusDispatchView.TAG, "ul: containBlockDirection is true resultFromParent !null ,direction:" + focusDirection);
|
|
1481
|
+
}
|
|
1482
|
+
return resultFromParent;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
if(mFocusListener != null && resultFromParent == null){
|
|
1486
|
+
final View v = mFocusListener.onFocusSearchFailed(focused,focusDirection,recycler,state);
|
|
1487
|
+
if(v != null){
|
|
1488
|
+
return v;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
if(LogUtils.isDebug()) {
|
|
1492
|
+
LogUtils.d("SingleList", "onFocusSearchFailed return super result:" + resultFromParent);
|
|
1493
|
+
}
|
|
1494
|
+
return resultFromParent;
|
|
1495
|
+
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
void shakeEndIfNeed(View focused, View result, int focusDirection) {
|
|
1499
|
+
if (mRecyclerView.mShakeEndEnable) {
|
|
1500
|
+
final View focusedChild = mRecyclerView.getFocusedChild();
|
|
1501
|
+
boolean isDirectionRight;
|
|
1502
|
+
if (orientation == HORIZONTAL) {
|
|
1503
|
+
isDirectionRight = focusDirection == FOCUS_RIGHT;
|
|
1504
|
+
} else {
|
|
1505
|
+
isDirectionRight = focusDirection == FOCUS_DOWN;
|
|
1506
|
+
}
|
|
1507
|
+
if (focusedChild != null && isDirectionRight) {
|
|
1508
|
+
final int pos = getPosition(focusedChild);
|
|
1509
|
+
final int itemCount = getItemCount();
|
|
1510
|
+
final boolean shake = pos > itemCount - mRecyclerView.shakePreCheckNumber && (focused == result || result == null);
|
|
1511
|
+
if (LogUtils.isDebug()) {
|
|
1512
|
+
LogUtils.d(TAG, "shakeEndIfNeed pos:" + pos + " ,itemCount:" + itemCount + " focused == result:" + (focused == result) + ",result:" + result);
|
|
1513
|
+
}
|
|
1514
|
+
if (shake) {
|
|
1515
|
+
// mRecyclerView.exeShakeRecycleView();
|
|
1516
|
+
mRecyclerView.exeShakeSelf(focused, focusDirection);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
private boolean animRunning = false;
|
|
1523
|
+
|
|
1524
|
+
private void shakeSelf(View view, int direction) {
|
|
1525
|
+
if (!animRunning) {
|
|
1526
|
+
animRunning = true;
|
|
1527
|
+
ObjectAnimator shakeSelfAnim;//抖动幅度0到5
|
|
1528
|
+
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
|
|
1529
|
+
shakeSelfAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y.getName(), 0, 5f);
|
|
1530
|
+
} else {
|
|
1531
|
+
shakeSelfAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X.getName(), 0, 5f);
|
|
1532
|
+
}
|
|
1533
|
+
shakeSelfAnim.setDuration(250);//持续时间
|
|
1534
|
+
shakeSelfAnim.setInterpolator(new CycleInterpolator(2));//抖动次数
|
|
1535
|
+
shakeSelfAnim.addListener(new AnimatorListenerAdapter() {
|
|
1536
|
+
@Override
|
|
1537
|
+
public void onAnimationCancel(Animator animation) {
|
|
1538
|
+
animRunning = false;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
@Override
|
|
1542
|
+
public void onAnimationEnd(Animator animation) {
|
|
1543
|
+
animRunning = false;
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
shakeSelfAnim.start();//开始动画
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
@Override
|
|
1551
|
+
public void onLayoutChildren(Recycler recycler, State state) {
|
|
1552
|
+
super.onLayoutChildren(recycler, state);
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
@Override
|
|
1556
|
+
public void layoutDecorated(View child, int left, int top, int right, int bottom) {
|
|
1557
|
+
super.layoutDecorated(child, left, top, right, bottom);
|
|
1558
|
+
final int pos = getPosition(child);
|
|
1559
|
+
if (LogUtils.isDebug()) {
|
|
1560
|
+
LogUtils.d(TAG, "layoutDecorated pos:" + pos + ",defaultSectionPosition:" + mRecyclerView.defaultSectionPosition);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
|
|
1564
|
+
if (mRecyclerView.defaultSectionPosition == pos && pos > -1) {
|
|
1565
|
+
mRecyclerView.changeSelectState(child, true);
|
|
1566
|
+
} else {
|
|
1567
|
+
mRecyclerView.changeSelectState(child, false);
|
|
1568
|
+
}
|
|
1569
|
+
if (mRecyclerView.layoutTriggerTargetPosition > -1) {
|
|
1570
|
+
if (mRecyclerView.layoutTriggerTargetPosition == pos) {
|
|
1571
|
+
TriggerTaskManagerModule.dispatchTriggerTask(mRecyclerView, "onTargetChildLayout");
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
if (LogUtils.isDebug()) {
|
|
1576
|
+
Log.d(FocusDispatchView.TAG, "layoutDecorated pos:" + pos + "view:" + child.getId() + ",parenID:" + mRecyclerView.getId());
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
private static final class ReFocus {
|
|
1583
|
+
final int oldPosition;
|
|
1584
|
+
final View oldFocus;
|
|
1585
|
+
final View oldChild;
|
|
1586
|
+
boolean valid = true;
|
|
1587
|
+
boolean inReFocus = false;
|
|
1588
|
+
|
|
1589
|
+
private ReFocus(int oldPosition, View oldFocus, View oldChild) {
|
|
1590
|
+
this.oldPosition = oldPosition;
|
|
1591
|
+
this.oldFocus = oldFocus;
|
|
1592
|
+
this.oldChild = oldChild;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
@Override
|
|
1596
|
+
public String toString() {
|
|
1597
|
+
return "ReFocus{" +
|
|
1598
|
+
"oldPosition=" + oldPosition +
|
|
1599
|
+
", oldFocus=" + oldFocus +
|
|
1600
|
+
", oldChild=" + oldChild +
|
|
1601
|
+
", valid=" + valid +
|
|
1602
|
+
'}';
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
private static final class InitParams {
|
|
1607
|
+
int customFocusPosition;
|
|
1608
|
+
int targetFocusPosition;
|
|
1609
|
+
int scrollToPosition;
|
|
1610
|
+
int scrollOffset;
|
|
1611
|
+
String targetName;
|
|
1612
|
+
boolean valid = true;
|
|
1613
|
+
final boolean blockOthers;
|
|
1614
|
+
int delay;
|
|
1615
|
+
|
|
1616
|
+
private InitParams(int targetFocusPosition, int scrollToPosition, int scrollOffset, String targetName, boolean blockOthers, int delay) {
|
|
1617
|
+
this.targetFocusPosition = targetFocusPosition;
|
|
1618
|
+
this.customFocusPosition = targetFocusPosition;
|
|
1619
|
+
this.scrollToPosition = scrollToPosition;
|
|
1620
|
+
this.scrollOffset = scrollOffset;
|
|
1621
|
+
this.targetName = targetName;
|
|
1622
|
+
this.blockOthers = blockOthers;
|
|
1623
|
+
this.delay = delay;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
@Override
|
|
1627
|
+
public String toString() {
|
|
1628
|
+
return "PendingFocus{" +
|
|
1629
|
+
"targetPosition=" + targetFocusPosition +
|
|
1630
|
+
",customFocusPosition=" + customFocusPosition +
|
|
1631
|
+
",scrollToPosition=" + scrollToPosition +
|
|
1632
|
+
",scrollOffset=" + scrollOffset +
|
|
1633
|
+
", targetName='" + targetName + '\'' +
|
|
1634
|
+
", valid=" + valid +
|
|
1635
|
+
", blockOthers=" + blockOthers +
|
|
1636
|
+
", delay=" + delay +
|
|
1637
|
+
'}';
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
|
|
1642
|
+
private void stopListenGlobalFocusChange() {
|
|
1643
|
+
if (mOnGlobalFocusChangeListener != null) {
|
|
1644
|
+
getViewTreeObserver().removeOnGlobalFocusChangeListener(mOnGlobalFocusChangeListener);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
private void listenGlobalFocusChangeIfNeed() {
|
|
1649
|
+
stopListenGlobalFocusChange();
|
|
1650
|
+
if (forceListenGlobalFocusChange) {
|
|
1651
|
+
mOnGlobalFocusChangeListener = new ViewTreeObserver.OnGlobalFocusChangeListener() {
|
|
1652
|
+
@Override
|
|
1653
|
+
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
|
|
1654
|
+
if (LogUtils.isDebug()) {
|
|
1655
|
+
Log.d(TAG, "onGlobalFocusChanged hasFocus : " + hasFocus() + " this :" + this);
|
|
1656
|
+
}
|
|
1657
|
+
if (hasFocus()) {
|
|
1658
|
+
if (oldFocus == null) {
|
|
1659
|
+
//首次获得焦点
|
|
1660
|
+
notifyRecyclerViewFocusChanged(true, false, null, newFocus, false);
|
|
1661
|
+
} else {
|
|
1662
|
+
//焦点在内部,但上一个view不属于内部
|
|
1663
|
+
final boolean isOldFocusDescendantOf = TVViewUtil.isViewDescendantOf(oldFocus, TVRecyclerView.this);
|
|
1664
|
+
if (!isOldFocusDescendantOf) {
|
|
1665
|
+
notifyRecyclerViewFocusChanged(true, false, oldFocus, newFocus, false);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
} else {
|
|
1669
|
+
final boolean isNewFocusDescendantOf = TVViewUtil.isViewDescendantOf(newFocus, TVRecyclerView.this);
|
|
1670
|
+
if (LogUtils.isDebug()) {
|
|
1671
|
+
Log.d(TAG, "onGlobalFocusChanged hasFocus : " + hasFocus() + " isNewFocusDescendantOf : " + isNewFocusDescendantOf);
|
|
1672
|
+
}
|
|
1673
|
+
if (!isNewFocusDescendantOf) {
|
|
1674
|
+
//焦点丢失
|
|
1675
|
+
final boolean isOldFocusDescendantOf = TVViewUtil.isViewDescendantOf(oldFocus, TVRecyclerView.this);
|
|
1676
|
+
|
|
1677
|
+
if (isOldFocusDescendantOf) {
|
|
1678
|
+
notifyRecyclerViewFocusChanged(false, true, oldFocus, newFocus, true);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
getViewTreeObserver().addOnGlobalFocusChangeListener(mOnGlobalFocusChangeListener);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
protected boolean forceListenGlobalFocusChange = true;
|
|
1689
|
+
private ViewTreeObserver.OnGlobalFocusChangeListener mOnGlobalFocusChangeListener;
|
|
1690
|
+
|
|
1691
|
+
boolean lastFocusState = false;
|
|
1692
|
+
|
|
1693
|
+
private void notifyRecyclerViewFocusChanged(boolean hasFocus, boolean isOldFocusDescendantOf, View oldFocus, View focused, boolean loseFocus) {
|
|
1694
|
+
//
|
|
1695
|
+
if (LogUtils.isDebug()) {
|
|
1696
|
+
Log.d(TAG, "notifyRecyclerViewFocusChanged lastFocusState != hasFocus:" + (lastFocusState != hasFocus) + " ,enableSelectOnFocus:" + enableSelectOnFocus + ",loseFocus:" + loseFocus + ",isOldFocusDescendantOf:" + isOldFocusDescendantOf);
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
if (lastFocusState != hasFocus) {
|
|
1700
|
+
onRecyclerViewFocusChanged(hasFocus, focused);
|
|
1701
|
+
}
|
|
1702
|
+
if (lastFocusState != hasFocus && (enableSelectOnFocus || loseFocus)) {
|
|
1703
|
+
final View selectedChild = findSelectedChild();
|
|
1704
|
+
if (!hasFocus && isOldFocusDescendantOf) {
|
|
1705
|
+
if (selectedChild != null) {
|
|
1706
|
+
if (focused != selectedChild) {
|
|
1707
|
+
changeSelectState(selectedChild, true);
|
|
1708
|
+
}
|
|
1709
|
+
if (LogUtils.isDebug()) {
|
|
1710
|
+
LogUtils.v("hippyState", "+++setState true child:" + selectedChild);
|
|
1711
|
+
}
|
|
1712
|
+
callItemStateChangeIfNeed(selectedChild, StateListPresenter.STATE_SELECTED);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
lastFocusState = hasFocus;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
protected void onRecyclerViewFocusChanged(boolean hasFocus, View focused) {
|
|
1720
|
+
//
|
|
1721
|
+
if (LogUtils.isDebug()) {
|
|
1722
|
+
Log.d(TAG, "onRecyclerViewFocusChanged hasFocus : " + hasFocus + " this :" + this);
|
|
1723
|
+
}
|
|
1724
|
+
if (LogUtils.isDebug()) {
|
|
1725
|
+
LogUtils.d(TAG, "onRecyclerViewFocusChanged context:" + getHippyContext());
|
|
1726
|
+
}
|
|
1727
|
+
if (getHippyContext() != null) {
|
|
1728
|
+
if (hasFocus) {
|
|
1729
|
+
TriggerTaskManagerModule.dispatchTriggerTask(this, "onFocusAcquired");
|
|
1730
|
+
} else {
|
|
1731
|
+
TriggerTaskManagerModule.dispatchTriggerTask(this, "onFocusLost");
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
/****edit by zhaopeng 20201117 TV端取消滚动*/
|
|
1738
|
+
@Override
|
|
1739
|
+
public void setOverScrollEnabled(boolean up, boolean down) {
|
|
1740
|
+
super.setOverScrollEnabled(false, false);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
@Override
|
|
1744
|
+
public void setOverScrollEnabled(boolean enable) {
|
|
1745
|
+
super.setOverScrollEnabled(false);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
|
|
1749
|
+
private RecycleViewFlinger mFlinger;
|
|
1750
|
+
|
|
1751
|
+
@Override
|
|
1752
|
+
public boolean dispatchKeyEventPreIme(KeyEvent event) {
|
|
1753
|
+
if (mFlinger == null) {
|
|
1754
|
+
mFlinger = new NegativeLongKeyFlinger(this);
|
|
1755
|
+
mFlinger.setVertical(this.orientation == BaseLayoutManager.VERTICAL);
|
|
1756
|
+
}
|
|
1757
|
+
//接收事件
|
|
1758
|
+
return mFlinger != null && mFlinger.dispatchKeyEventPreIme(event) || super.dispatchKeyEventPreIme(event);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
//zhaopeng add
|
|
1762
|
+
private boolean mEnableChildFocusEvent = false;
|
|
1763
|
+
private boolean mEnableScrollOffsetEvent = false;
|
|
1764
|
+
|
|
1765
|
+
public void setEnableScrollOffsetEvent(boolean mEnableScrollOffsetEvent) {
|
|
1766
|
+
this.mEnableScrollOffsetEvent = mEnableScrollOffsetEvent;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
private HippyViewEvent mChildFocusEvent;
|
|
1770
|
+
|
|
1771
|
+
@Override
|
|
1772
|
+
public void setDispatchChildFocusEvent(boolean enable) {
|
|
1773
|
+
//
|
|
1774
|
+
this.mEnableChildFocusEvent = enable;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
@Override
|
|
1778
|
+
public View getHostView() {
|
|
1779
|
+
return this;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
@Override
|
|
1784
|
+
protected HippyMap generateScrollEvent() {
|
|
1785
|
+
|
|
1786
|
+
return super.generateScrollEvent();
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
@Override
|
|
1790
|
+
protected void dispatchLayout() {
|
|
1791
|
+
super.dispatchLayout();
|
|
1792
|
+
handleScrollValue();
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
@Override
|
|
1796
|
+
protected void handleFocusAfterLayout(Recycler recycler, State state, boolean dataChanged) {
|
|
1797
|
+
super.handleFocusAfterLayout(recycler, state, dataChanged);
|
|
1798
|
+
handleScrollValue();
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
private void handleScrollValue() {
|
|
1802
|
+
handleScrollValue(false);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
|
|
1806
|
+
protected void onScrollYChange(int scrollY) {
|
|
1807
|
+
if (mEnableScrollOffsetEvent) {
|
|
1808
|
+
getOnScrollYOffsetChanged().send(this, generateScrollOffsetEvent(scrollY));
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
HippyViewEvent mOnScrollYChanged;
|
|
1813
|
+
|
|
1814
|
+
protected HippyViewEvent getOnScrollYOffsetChanged() {
|
|
1815
|
+
if (mOnScrollYChanged == null) {
|
|
1816
|
+
mOnScrollYChanged = new HippyViewEvent("onScrollOffset");
|
|
1817
|
+
}
|
|
1818
|
+
return mOnScrollYChanged;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
protected HippyMap generateScrollOffsetEvent(int offsetY) {
|
|
1822
|
+
HippyMap event = new HippyMap();
|
|
1823
|
+
event.pushDouble("y", offsetY);
|
|
1824
|
+
return event;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
@Override
|
|
1829
|
+
public void onScrolled(int x, int y) {
|
|
1830
|
+
super.onScrolled(x, y);
|
|
1831
|
+
handleScrollValue();
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
@Override
|
|
1835
|
+
protected void onSendScrollEvent() {
|
|
1836
|
+
super.onSendScrollEvent();
|
|
1837
|
+
onScrollYChange(mOffsetY);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
private int lastOffsetY = 0;
|
|
1841
|
+
|
|
1842
|
+
private void handleScrollValue(boolean force) {
|
|
1843
|
+
final int sy = mOffsetY;
|
|
1844
|
+
final int delta = sy - lastOffsetY;
|
|
1845
|
+
lastOffsetY = sy;
|
|
1846
|
+
int vector = 0;
|
|
1847
|
+
if (delta > 0) {
|
|
1848
|
+
vector = 1;
|
|
1849
|
+
}
|
|
1850
|
+
if (delta < 0) {
|
|
1851
|
+
vector = -1;
|
|
1852
|
+
}
|
|
1853
|
+
if (LogUtils.isDebug()) {
|
|
1854
|
+
LogUtils.d("ScrollLog", "handleScrollValue vector" + vector + ",force:" + force);
|
|
1855
|
+
}
|
|
1856
|
+
if (scrollYGreaterReferenceValue > -1 && vector > 0) {
|
|
1857
|
+
if (LogUtils.isDebug()) {
|
|
1858
|
+
LogUtils.v("ScrollLog", "scrollYGreaterCheckPoint:" + scrollYGreaterCheckPoint + ",offsetY:" + sy + ",scrollYGreaterReferenceValue:" + scrollYGreaterReferenceValue);
|
|
1859
|
+
}
|
|
1860
|
+
if (sy >= scrollYGreaterReferenceValue && (force || (scrollYGreaterCheckPoint <= scrollYGreaterReferenceValue))) {
|
|
1861
|
+
//第一次触发
|
|
1862
|
+
scrollYGreaterCheckPoint = sy;
|
|
1863
|
+
scrollYLesserCheckPoint = sy;
|
|
1864
|
+
if (LogUtils.isDebug()) {
|
|
1865
|
+
LogUtils.d("ScrollLog", "++++onScrollValueGreater sy:" + sy + ",force:" + force);
|
|
1866
|
+
}
|
|
1867
|
+
TriggerTaskManagerModule.dispatchTriggerTask(this, "onScrollYGreater");
|
|
1868
|
+
new HippyViewEvent("onScrollYGreaterReference").send(this, null);
|
|
1869
|
+
} else {
|
|
1870
|
+
if (LogUtils.isDebug()) {
|
|
1871
|
+
LogUtils.d("ScrollLog", "scrollYGreaterCheckPoint fail sy:" + sy + ",force:" + force + ",scrollYGreaterCheckPoint:" + scrollYGreaterCheckPoint);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
if (scrollYLesserReferenceValue > -1 && vector < 0) {
|
|
1877
|
+
if (LogUtils.isDebug()) {
|
|
1878
|
+
LogUtils.v("ScrollLog", "scrollYLesserCheckPoint:" + scrollYLesserCheckPoint + ",offsetY:" + sy + ",scrollYLesserReferenceValue:" + scrollYLesserReferenceValue);
|
|
1879
|
+
}
|
|
1880
|
+
if (sy <= scrollYLesserReferenceValue && (force || (scrollYLesserCheckPoint >= scrollYLesserReferenceValue))) {
|
|
1881
|
+
if (LogUtils.isDebug()) {
|
|
1882
|
+
LogUtils.d("ScrollLog", "---onScrollValueLesser sy:" + sy + ",force:" + force);
|
|
1883
|
+
}
|
|
1884
|
+
scrollYLesserCheckPoint = sy;
|
|
1885
|
+
scrollYGreaterCheckPoint = sy;
|
|
1886
|
+
TriggerTaskManagerModule.dispatchTriggerTask(this, "onScrollYLesser");
|
|
1887
|
+
new HippyViewEvent("onScrollYLesserReference").send(this, null);
|
|
1888
|
+
} else {
|
|
1889
|
+
if (LogUtils.isDebug()) {
|
|
1890
|
+
LogUtils.d("ScrollLog", "scrollYLesserCheckPoint fail sy:" + sy + ",force:" + force + ",scrollYLesserCheckPoint:" + scrollYLesserCheckPoint);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
public void setCheckScrollOffsetOnStateChanged(boolean b) {
|
|
1898
|
+
this.checkScrollOffsetOnStateChanged = b;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
private boolean checkScrollOffsetOnStateChanged = false;
|
|
1902
|
+
|
|
1903
|
+
@Override
|
|
1904
|
+
public void onScrollStateChanged(int oldState, int newState) {
|
|
1905
|
+
super.onScrollStateChanged(oldState, newState);
|
|
1906
|
+
if (checkScrollOffsetOnStateChanged && newState == SCROLL_STATE_IDLE) {
|
|
1907
|
+
LogUtils.d("ScrollLog", "onScrollState Changed handleScrollValue offsetY:" + mOffsetY + ",oldState:" + oldState);
|
|
1908
|
+
handleScrollValue(true);
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
void resetScrollY() {
|
|
1913
|
+
LogUtils.w("ScrollLog", "resetScrollY");
|
|
1914
|
+
scrollYGreaterCheckPoint = -1;
|
|
1915
|
+
scrollYLesserCheckPoint = -1;
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
|
|
1919
|
+
private int scrollYGreaterCheckPoint = 0;
|
|
1920
|
+
private int scrollYLesserCheckPoint = 0;
|
|
1921
|
+
|
|
1922
|
+
|
|
1923
|
+
private int scrollYLesserReferenceValue = -1;
|
|
1924
|
+
private int scrollYGreaterReferenceValue = -1;
|
|
1925
|
+
|
|
1926
|
+
public void setScrollYLesserReferenceValue(int scrollYLesserReferenceValue) {
|
|
1927
|
+
this.scrollYLesserReferenceValue = scrollYLesserReferenceValue;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
public void setScrollYGreaterReferenceValue(int scrollYGreaterReferenceValue) {
|
|
1931
|
+
this.scrollYGreaterReferenceValue = scrollYGreaterReferenceValue;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* zhaopeng add
|
|
1936
|
+
*/
|
|
1937
|
+
private boolean isPageHidden = false;
|
|
1938
|
+
|
|
1939
|
+
protected void onPageHiddenChanged(boolean hidden) {
|
|
1940
|
+
this.isPageHidden = hidden;
|
|
1941
|
+
if (hidden) {
|
|
1942
|
+
stopListenGlobalFocusChange();
|
|
1943
|
+
} else {
|
|
1944
|
+
listenGlobalFocusChangeIfNeed();
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
@Override
|
|
1949
|
+
public boolean isPageHidden() {
|
|
1950
|
+
return isPageHidden;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
@Override
|
|
1954
|
+
public void changePageHidden(boolean hidden) {
|
|
1955
|
+
onPageHiddenChanged(hidden);
|
|
1956
|
+
for (int i = 0; i < getChildCount(); i++) {
|
|
1957
|
+
final View v = getChildAt(i);
|
|
1958
|
+
if (v instanceof ExtendViewGroup) {
|
|
1959
|
+
((ExtendViewGroup) v).changePageHidden(hidden);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
@Override
|
|
1965
|
+
public void onRequestAutofocus(View child, View target, int type) {
|
|
1966
|
+
if(this.getVisibility() != View.VISIBLE){
|
|
1967
|
+
Log.e(AutoFocusManager.TAG,"onRequestAutofocus return on parent visibility != View.VISIBLE,"+ExtendUtil.debugView(this)+",target:"+ExtendUtil.debugView(target));
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
if (getParent() instanceof ExtendViewGroup) {
|
|
1971
|
+
ExtendViewGroup parent = (ExtendViewGroup) getParent();
|
|
1972
|
+
parent.onRequestAutofocus(this, target,type);
|
|
1973
|
+
} else {
|
|
1974
|
+
Log.i(AutoFocusManager.TAG, "onRequestAutofocus parent is not a instance of ExtendViewGroup parent: " + getParent());
|
|
1975
|
+
//AutoFocusManager.globalRequestFocus(target);
|
|
1976
|
+
final AutoFocusManager af = AutoFocusManager.findAutoFocusManagerFromRoot(this);
|
|
1977
|
+
if (af != null) {
|
|
1978
|
+
af.requestGlobalRequestFocus(this,target,type);
|
|
1979
|
+
}else{
|
|
1980
|
+
Log.e(AutoFocusManager.TAG, "onRequestAutofocus requestFocus on PageRoot af is null");
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
private boolean skipRequestFocus = false;
|
|
1986
|
+
|
|
1987
|
+
@Override
|
|
1988
|
+
public void setSkipRequestFocus(boolean b) {
|
|
1989
|
+
this.skipRequestFocus = b;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
@Override
|
|
1993
|
+
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
|
|
1994
|
+
if(skipRequestFocus){
|
|
1995
|
+
Log.e(AutoFocusManager.TAG,"requestFocus return false on skipRequestFocus this:"+this);
|
|
1996
|
+
return false;
|
|
1997
|
+
}
|
|
1998
|
+
return super.requestFocus(direction, previouslyFocusedRect);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
private ListViewControlProp listViewControlProp;
|
|
2002
|
+
|
|
2003
|
+
@Override
|
|
2004
|
+
public ListViewControlProp getControlProps() {
|
|
2005
|
+
if (listViewControlProp == null) {
|
|
2006
|
+
listViewControlProp = new ListViewControlProp();
|
|
2007
|
+
}
|
|
2008
|
+
return listViewControlProp;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
public void setAutoscrollPosition(int position,boolean force,int offset){
|
|
2012
|
+
Log.i(AutoFocusManager.TAG, ">list setAutoscrollPosition :" + position+",focusChildPos:"+mFocusChildPosition);
|
|
2013
|
+
if(getControlProps().autoScrollToPosition != position || force){
|
|
2014
|
+
getControlProps().autoScrollToPosition = position;
|
|
2015
|
+
getControlProps().scrollOffset = offset;
|
|
2016
|
+
if(getControlProps().autofocusPosition == position && hasFocus()){
|
|
2017
|
+
Log.e(AutoFocusManager.TAG, ">list setAutoscrollPosition return on autofocusPosition == position :" + position);
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
if (getControlProps().autoScrollToPosition == -1) {
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
final int focusChildPos = mFocusChildPosition;
|
|
2024
|
+
if(focusChildPos == position && hasFocus()){
|
|
2025
|
+
Log.e(AutoFocusManager.TAG, ">list setAutoscrollPosition return on focusChildPos == position :" + position);
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
// HippyMap hippyMap = new HippyMap();setAutoscrollPosition
|
|
2029
|
+
// hippyMap.pushInt("scrollToPosition",position);
|
|
2030
|
+
// hippyMap.pushBoolean("alignCenter",true);
|
|
2031
|
+
// setInitPositionInfo(hippyMap);
|
|
2032
|
+
if(!hasFocus() || getChildCount() < 1) {
|
|
2033
|
+
setTargetFocusChildPosition(position);
|
|
2034
|
+
// int diffScroll = Math.abs(getControlProps().currentScrollToPosition - position);
|
|
2035
|
+
boolean anim = false;
|
|
2036
|
+
// final View view = findViewByPosition(position);
|
|
2037
|
+
// if (view != null) {
|
|
2038
|
+
// anim = true;
|
|
2039
|
+
// }
|
|
2040
|
+
scrollToPosition4Autoscroll(position, anim);
|
|
2041
|
+
// HippyMap hippyMap = new HippyMap();
|
|
2042
|
+
// hippyMap.pushInt("scrollToPosition",position);
|
|
2043
|
+
// hippyMap.pushBoolean("alignCenter",true);
|
|
2044
|
+
// setInitPositionInfo(hippyMap);
|
|
2045
|
+
}else{
|
|
2046
|
+
Log.e(AutoFocusManager.TAG, ">list setAutoscrollPosition return on hasFocus position :" + position);
|
|
2047
|
+
}
|
|
2048
|
+
//scrollToPosition(position);
|
|
2049
|
+
}else{
|
|
2050
|
+
Log.e(AutoFocusManager.TAG, ">list setAutoscrollPosition return on autoScrollToPosition == position :" + position);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
public void scrollToPosition4Autoscroll(int pos, boolean anim){
|
|
2055
|
+
if(getSingleLineLayoutManager().childOnScreenScroller.type == TVRecyclerView.REQUEST_CHILD_ON_SCREEN_TYPE_CENTER){
|
|
2056
|
+
getControlProps().pendingScrollToPosition = pos;
|
|
2057
|
+
}
|
|
2058
|
+
int offset = getControlProps().scrollOffset;
|
|
2059
|
+
if(LogUtils.isDebug()) {
|
|
2060
|
+
Log.i(AutoFocusManager.TAG, "handleAutoscroll scrollToPositionWithAlignCenter pos:" + pos + ",offset:" + offset + ",getControlProps().pendingScrollToPosition:" + getControlProps().pendingScrollToPosition);
|
|
2061
|
+
}
|
|
2062
|
+
//setupInitScrollWork(-1,pos,offset,null,false,0,false);
|
|
2063
|
+
this.scrollToPosition(pos,offset);
|
|
2064
|
+
// this.updateList(anim);
|
|
2065
|
+
// RenderUtil.req
|
|
2066
|
+
// RenderUtil.requestNodeLayout(this);
|
|
2067
|
+
}
|
|
2068
|
+
/** zhaopeng add*/
|
|
2069
|
+
|
|
2070
|
+
}
|