当前位置:网站首页>Swiperefreshlayout+recyclerview failed to pull down troubleshooting
Swiperefreshlayout+recyclerview failed to pull down troubleshooting
2022-06-25 08:39:00 【Shen Ye】
background
stay Android In development ,SwipeRefreshLayout+RecyclerView Of UI The pattern helps developers easily provide the ability of pull-down refresh , But in previous development , I met a SwipeRefreshLayout Problems that cannot be pulled down .
The specific problem is , I need to go through RecyclerView Show a series of content , The displayed content is distributed according to the server , For example, you need to show Banner, Recommendation list, etc . Later, during the second phase of development , This interface needs to add a small feature, The server may not issue Banner Related properties , But because of the previous Adapter There is some logic in , As a result, if it is not issued Banner Data words ,RecyclerView Will still show Banner Corresponding ViewHolder, And this ViewHolder Empty to display . To solve this problem , I am here Adapter A new... Has been added to the ViewType And corresponding ViewHolder:EmptyViewHolder. This ViewHolder Corresponding Layout That's true :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp">
</RelativeLayout>
But this will lead to the problems mentioned in this article ,SwipeRefreshLayout Unable to pull down refresh , Simply speaking , Is that when RecyclerView Of the 0 Height View The height of 0 when ,SwipeRefreshLayout Unable to pull down refresh .
analysis
Observe SwipeRefreshLayout Unable to pull down ,RecyclerView When you pull down, something appears RippleEffect, It is obvious that it was originally required by SwipeRefreshLayout Handle the pull-down gesture , By RecyclerView The consumption . As for this gesture RecyclerView Reasons for consumption , according to Android Of View The principle of event distribution , A reasonable guess is SwipeRefreshLayout There is a problem with the distribution or interception of this event .
dispatchTouchEvent
SwipeRefreshLayout Inherited from ViewGroup, And does not rewrite itself dispatchTouchEvent, So the problem is probably not here .
onInterceptTouchEvent
onInterceptTouchEvent This method is responsible for intercepting events . The basic implementation of this method is :
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Omitted code
if (!isEnabled() || mReturningToStart || canChildScrollUp()
|| mRefreshing || mNestedScrollInProgress) {
// Fail fast if we're not in a state where a swipe is possible
return false;
}
// Omitted code
return true;
}
according to bug What happened and the code , This if The judgment is very suspicious , The probability is that there is a lot of judgment true, Lead to the whole method return false, The incident was not stopped . therefore canChildScrollUp() This judgment is very suspicious . according to SwipeRefreshLayout The law of operation , You can guess when RecyclerView When it can slide ,canChildScrollUp() by true,SwipeRefreshLayout Do not block gestures ,RecyclerView Can slide up and down normally ; When RecyclerView In slide to 0 individual item, And continue to pull down ,canChildScrollUp() return false, The incident was SwipeRefreshLayout Intercept .
canChildScrollUp() The source code of the method is as follows :
/**
* @return Whether it is possible for the child view of this layout to
* scroll up. Override this if the child view is a custom view.
*/
public boolean canChildScrollUp() {
if (mChildScrollUpCallback != null) {
return mChildScrollUpCallback.canChildScrollUp(this, mTarget);
}
if (mTarget instanceof ListView) {
return ListViewCompat.canScrollList((ListView) mTarget, -1);
}
return mTarget.canScrollVertically(-1);
}
This note is very interesting , Remind us if SwipeRefreshLayout The son of View It's a custom View, This method has to be rewritten , tell SwipeRefreshLayout Son View Can I slide . ( I didn't know this before , So the level of the source code will be improved )
Code logic , There are three branches here , Just look at the code , I don't know which branch to take , Forget it , direct debug Well .
Debug
adopt debug It can be seen that the final branch is taken , there mTarget It's the son View, namely RecyclerView, But think about it later Debug RecyclerView#canScrollVertically() when ` You will find that the number of lines of code does not correspond to . This is because the domestic manufacturers will be Android Customize the system source code , Recommended here Android Studio Self contained Simulator , Use the original operating system Debug.
Start simulator , restart Debug.
/**
* Check if this view can be scrolled vertically in a certain direction.
*
* @param direction Negative to check scrolling up, positive to check scrolling down.
* @return true if this view can be scrolled in the specified direction, false otherwise.
*/
public boolean canScrollVertically(int direction) {
final int offset = computeVerticalScrollOffset();
final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
if (range == 0) return false;
if (direction < 0) {
return offset > 0;
} else {
return offset < range - 1;
}
}
The point is that final int offset = computeVerticalScrollOffset();, here offset Returned a greater than 0 Value , This causes the entire method to return true.
Let's see it again computeVerticalScrollOffset() What happened? .
/**
* <p>Compute the vertical offset of the vertical scrollbar's thumb within the vertical range.
* This value is used to compute the length of the thumb within the scrollbar's track. </p>
*
* <p>The range is expressed in arbitrary units that must be the same as the units used by
* {@link #computeVerticalScrollRange()} and {@link #computeVerticalScrollExtent()}.</p>
*
* <p>Default implementation returns 0.</p>
*
* <p>If you want to support scroll bars, override
* {@link RecyclerView.LayoutManager#computeVerticalScrollOffset(RecyclerView.State)} in your
* LayoutManager.</p>
*
* @return The vertical offset of the scrollbar's thumb
* @see RecyclerView.LayoutManager#computeVerticalScrollOffset
* (RecyclerView.State)
*/
@Override
public int computeVerticalScrollOffset() {
if (mLayout == null) {
return 0;
}
return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollOffset(mState) : 0;
}
Here we give the calculation of the vertical offset to layoutManager To do , We're going to use LinearLayoutManager, Continue to look at the source code . After a few jumps , Arrived ScrollbarHelper#computeScrollOffset(), The core code is as follows :
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled, boolean reverseLayout) {
// Omitted code ...
final int minPosition = //.... Visible page 0 individual item
final int maxPosition = //... The last visible item
final int itemsBefore = //... Visible page 0 individual item In front of item The number of
//
final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild)
- orientation.getDecoratedStart(startChild));// Last visible item The bottom split line of the to 0 A visible item Top style line
final int itemRange = Math.abs(lm.getPosition(startChild)
- lm.getPosition(endChild)) + 1;
// so item The number of
final float avgSizePerRow = (float) laidOutArea / itemRange;
// Every item The average height of
return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
- orientation.getDecoratedStart(startChild)));// Calculate how far you can slide
}
The general logic here is as follows , First, find the first and last... Visible on the screen item Of position, Already these two item Distance between , Then calculate each item The average height of , forecast recyclerview The sliding distance . for instance , Currently visible 3 individual item,position And height respectively 0->100px,1->200px,2->300p, So here itemRange Namely 2-0+1=3, The average height is 600/3=200px,itemBefore by 0, So the final result is that you can slide 0*200px = 0px. Change the scene , The current courseware is 3 individual item,position And height respectively 1->100px,2->200px,3->300p, here itemBefore for 1, Therefore, the calculation result is 200px.
So in this scenario , The first 0 individual item The height is 0 invisible , The first 0 A visible item Of position by 1, therefore itemBefore by 1, The result must be greater than 0.
So go back to the top canScrollVertically() Method , The return value is true, It can lead to swipeRefreshLayout Do not block gestures , Therefore, the pull-down refresh cannot be triggered .
terms of settlement
Set up EmptyViewHolder The height of 1px That's all right. . In this way, No 0 individual item It can be seen ,itemBefore = 0, The return value is 0,SwipeRefreshLayout You can intercept the event .
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1px">
</RelativeLayout>
边栏推荐
- linux中的mysql有10061错误怎么解决
- Is the securities account given by Qiantang education business school safe? Can I open an account?
- 35岁腾讯员工被裁员感叹:北京一套房,存款700多万,失业好焦虑
- 【515. 在每个树行中找最大值】
- Find the nearest common ancestor (Sword finger offer) of two nodes in the binary tree (search tree)
- Rqt command
- Jdbc-dao layer implementation
- Exchange:管理日历权限
- 想要软件测试效果好,搭建好测试环境是前提
- Unity Addressable批量管理
猜你喜欢

Beam search and five optimization methods

GPU calculation

View all listening events on the current page by browser
How to calculate the characteristic vector, weight value, CI value and other indicators in AHP?
![[QT] QT 5 procedure: print documents](/img/76/2fce505c43f75360a8ff477aa2d31d.png)
[QT] QT 5 procedure: print documents

Rank sum ratio (RSR) index calculation

How to calculate the fuzzy comprehensive evaluation index? How to calculate the four fuzzy operators?

leetcode. 13 --- Roman numeral to integer

Fault: 0x800ccc1a error when outlook sends and receives mail

家庭服务器门户Easy-Gate
随机推荐
打新债的安全性 有风险吗
城鏈科技平臺,正在實現真正意義上的價值互聯網重構!
Quickly build a real-time face mask detection system in five minutes (opencv+paddlehub with source code)
Getting to know the generation confrontation network (12) -- using pytoch to build wgan-gp to generate handwritten digits
Measure the current temperature
SwipeRefreshLayout+RecyclerView无法下拉问题排查
[QT] QT 5 procedure: print documents
家庭服务器门户Easy-Gate
初识生成对抗网络(12)——利用Pytorch搭建WGAN-GP生成手写数字
在网上股票开户安全吗?证券账户可以给别人用吗?
Data preprocessing: discrete feature coding method
Prepare these before the interview. The offer is soft. The general will not fight unprepared battles
How to analyze the coupling coordination index?
Is there any risk in making new bonds
现在网上开通股票账号安全吗?
leetcode.13 --- 罗马数字转整数
打新债真的安全吗? 风险大吗
Bluecmsv1.6- code audit
【操作教程】TSINGSEE青犀视频平台如何将旧数据库导入到新数据库?
Exchange:管理日历权限