Skip to content

Commit 8a06dc9

Browse files
committed
[Feature] Add FixOnItemTouchListenerRecyclerView.
1 parent 398bf16 commit 8a06dc9

1 file changed

Lines changed: 140 additions & 0 deletions

File tree

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package me.zhanghai.android.fastscroll;
18+
19+
import android.content.Context;
20+
import android.util.AttributeSet;
21+
import android.view.MotionEvent;
22+
23+
import java.util.ArrayList;
24+
import java.util.LinkedHashSet;
25+
import java.util.List;
26+
import java.util.Set;
27+
28+
import androidx.annotation.AttrRes;
29+
import androidx.annotation.NonNull;
30+
import androidx.annotation.Nullable;
31+
import androidx.recyclerview.widget.RecyclerView;
32+
33+
public class FixOnItemTouchListenerRecyclerView extends RecyclerView {
34+
35+
@NonNull
36+
private final OnItemTouchDispatcher mOnItemTouchDispatcher = new OnItemTouchDispatcher();
37+
38+
public FixOnItemTouchListenerRecyclerView(@NonNull Context context) {
39+
super(context);
40+
41+
init();
42+
}
43+
44+
public FixOnItemTouchListenerRecyclerView(@NonNull Context context,
45+
@Nullable AttributeSet attrs) {
46+
super(context, attrs);
47+
48+
init();
49+
}
50+
51+
public FixOnItemTouchListenerRecyclerView(@NonNull Context context,
52+
@Nullable AttributeSet attrs,
53+
@AttrRes int defStyleAttr) {
54+
super(context, attrs, defStyleAttr);
55+
56+
init();
57+
}
58+
59+
private void init() {
60+
super.addOnItemTouchListener(mOnItemTouchDispatcher);
61+
}
62+
63+
@Override
64+
public void addOnItemTouchListener(@NonNull OnItemTouchListener listener) {
65+
mOnItemTouchDispatcher.addListener(listener);
66+
}
67+
68+
@Override
69+
public void removeOnItemTouchListener(@NonNull OnItemTouchListener listener) {
70+
mOnItemTouchDispatcher.removeListener(listener);
71+
}
72+
73+
private static class OnItemTouchDispatcher implements OnItemTouchListener {
74+
75+
@NonNull
76+
private final List<OnItemTouchListener> mListeners = new ArrayList<>();
77+
78+
@NonNull
79+
private final Set<OnItemTouchListener> mTrackingListeners = new LinkedHashSet<>();
80+
81+
@Nullable
82+
private OnItemTouchListener mInterceptingListener;
83+
84+
public void addListener(@NonNull OnItemTouchListener listener) {
85+
mListeners.add(listener);
86+
}
87+
88+
public void removeListener(@NonNull OnItemTouchListener listener) {
89+
mListeners.remove(listener);
90+
mTrackingListeners.remove(listener);
91+
if (mInterceptingListener == listener) {
92+
mInterceptingListener = null;
93+
}
94+
}
95+
96+
// @see RecyclerView#findInterceptingOnItemTouchListener
97+
@Override
98+
public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
99+
@NonNull MotionEvent event) {
100+
int action = event.getAction();
101+
for (OnItemTouchListener listener : mListeners) {
102+
boolean intercepted = listener.onInterceptTouchEvent(recyclerView, event);
103+
if (action == MotionEvent.ACTION_CANCEL) {
104+
mTrackingListeners.remove(listener);
105+
continue;
106+
}
107+
if (intercepted) {
108+
mInterceptingListener = listener;
109+
mTrackingListeners.remove(listener);
110+
event.setAction(MotionEvent.ACTION_CANCEL);
111+
for (OnItemTouchListener trackingListener : mTrackingListeners) {
112+
trackingListener.onInterceptTouchEvent(recyclerView, event);
113+
}
114+
event.setAction(action);
115+
mTrackingListeners.clear();
116+
return true;
117+
} else {
118+
mTrackingListeners.add(listener);
119+
}
120+
}
121+
return false;
122+
}
123+
124+
@Override
125+
public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent event) {
126+
mInterceptingListener.onTouchEvent(recyclerView, event);
127+
int action = event.getAction();
128+
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
129+
mInterceptingListener = null;
130+
}
131+
}
132+
133+
@Override
134+
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
135+
for (OnItemTouchListener listener : mListeners) {
136+
listener.onRequestDisallowInterceptTouchEvent(disallowIntercept);
137+
}
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)