수평 RecyclerView와 SwipeRefreshLayout 충돌로 인해 RecyclerView가 굴러가기 어려운 문제 해결
8825 단어 RecyclerViewAndroid
문제
내가 개발한 응용 프로그램은 상술한 화면이 있다.그냥 Swipe Refresh Layout으로 어렵지 않은 Recycler View를 둘러싸는 거예요.<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
나는 이렇게 될 것이라고 생각한다.
그러던 어느 날 사내 점검에서'자꾸 굴러다니기 힘들다'고 지적을 받았어요.
확실히 비스듬한 방향으로 굴리면 가로로 굴리고 Swipe Refresh Layout 반응으로 사용하기 어려울 것 같아서 수정해 봤어요.
이유는 SwipeRefreshLayout입니다.
Swipe Refresh Layout이 스크롤에 지나치게 민감하게 반응하는 이유를 발견했습니다.따라서 사용자 정의 Swipe Refresh Layout은 손가락이 왼쪽으로 미끄러질 때만 반응하도록 수정됩니다.
수정 방법
코드 여기 있어요.class OnlyVerticalSwipeRefreshLayout(context: Context, attrs: AttributeSet) :
SwipeRefreshLayout(context, attrs) {
private var touchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop
private var prevX: Float = 0.toFloat()
private var declined: Boolean = false
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
return super.onInterceptTouchEvent(event)
}
}
요점1: scaledTouchSlop
scaledTouchSlop 공식 문서에 따라Distance in pixels a touch can wander before we think the user is scrolling
쓰다ユーザーがスクロールを開始したとOSが認識する前にスクロールできるピクセル距離
이렇게 해석했습니다.어쨌든 굴러가기 시작하는 순간 손가락의 이동 거리다.
포인트 2: onInterceptTouch 이벤트
onInterceptTouchEvent 상위 뷰는 하위 뷰에서 발생하는 이벤트를 모니터링합니다.또한 터치 이벤트가 부모 보기 이벤트라면true를 되돌려주고, 부모 보기가 이벤트를 빼앗지 않으면false를 되돌려줍니다.이 예에서 하위 뷰는 가로 RecyclerView이고 상위 뷰는 SwipeRefreshLayout입니다.
요점3: 손가락의 이동 거리에 따라 Swipe Refresh Layout이 사건을 빼앗을지 판단
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
바로 이 부분입니다.
ACTION_DOWN에서 첫 번째 탭 위치를 유지합니다.ACTION_OVE에서 x 방향의 이동 거리를 계산하고 이동 거리가 touchSlop을 초과하면 이벤트를 RecyclerView에 넣습니다.
마지막으로 SwipeRefreshLayout을 OnlyV-ticalSwipeRefreshLayout으로 변경하면 수정이 완료됩니다.
웹 페이지 정보
Reference
이 문제에 관하여(수평 RecyclerView와 SwipeRefreshLayout 충돌로 인해 RecyclerView가 굴러가기 어려운 문제 해결), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yukimarume87/items/c3ae3fbfdaef6804c4fb
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Swipe Refresh Layout이 스크롤에 지나치게 민감하게 반응하는 이유를 발견했습니다.따라서 사용자 정의 Swipe Refresh Layout은 손가락이 왼쪽으로 미끄러질 때만 반응하도록 수정됩니다.
수정 방법
코드 여기 있어요.class OnlyVerticalSwipeRefreshLayout(context: Context, attrs: AttributeSet) :
SwipeRefreshLayout(context, attrs) {
private var touchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop
private var prevX: Float = 0.toFloat()
private var declined: Boolean = false
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
return super.onInterceptTouchEvent(event)
}
}
요점1: scaledTouchSlop
scaledTouchSlop 공식 문서에 따라Distance in pixels a touch can wander before we think the user is scrolling
쓰다ユーザーがスクロールを開始したとOSが認識する前にスクロールできるピクセル距離
이렇게 해석했습니다.어쨌든 굴러가기 시작하는 순간 손가락의 이동 거리다.
포인트 2: onInterceptTouch 이벤트
onInterceptTouchEvent 상위 뷰는 하위 뷰에서 발생하는 이벤트를 모니터링합니다.또한 터치 이벤트가 부모 보기 이벤트라면true를 되돌려주고, 부모 보기가 이벤트를 빼앗지 않으면false를 되돌려줍니다.이 예에서 하위 뷰는 가로 RecyclerView이고 상위 뷰는 SwipeRefreshLayout입니다.
요점3: 손가락의 이동 거리에 따라 Swipe Refresh Layout이 사건을 빼앗을지 판단
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
바로 이 부분입니다.
ACTION_DOWN에서 첫 번째 탭 위치를 유지합니다.ACTION_OVE에서 x 방향의 이동 거리를 계산하고 이동 거리가 touchSlop을 초과하면 이벤트를 RecyclerView에 넣습니다.
마지막으로 SwipeRefreshLayout을 OnlyV-ticalSwipeRefreshLayout으로 변경하면 수정이 완료됩니다.
웹 페이지 정보
Reference
이 문제에 관하여(수평 RecyclerView와 SwipeRefreshLayout 충돌로 인해 RecyclerView가 굴러가기 어려운 문제 해결), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yukimarume87/items/c3ae3fbfdaef6804c4fb
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class OnlyVerticalSwipeRefreshLayout(context: Context, attrs: AttributeSet) :
SwipeRefreshLayout(context, attrs) {
private var touchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop
private var prevX: Float = 0.toFloat()
private var declined: Boolean = false
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
return super.onInterceptTouchEvent(event)
}
}
Distance in pixels a touch can wander before we think the user is scrolling
ユーザーがスクロールを開始したとOSが認識する前にスクロールできるピクセル距離
when (event.action) {
MotionEvent.ACTION_DOWN -> {
prevX = MotionEvent.obtain(event).x
declined = false // New action
}
MotionEvent.ACTION_MOVE -> {
val eventX = event.x
val xDiff = abs(eventX - prevX)
if (declined || xDiff > touchSlop) {
declined = true // Memorize
return false
}
}
}
Reference
이 문제에 관하여(수평 RecyclerView와 SwipeRefreshLayout 충돌로 인해 RecyclerView가 굴러가기 어려운 문제 해결), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yukimarume87/items/c3ae3fbfdaef6804c4fb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)