如何在 SwipeRefreshLayout 中调整向下滑动的距离?

Posted

技术标签:

【中文标题】如何在 SwipeRefreshLayout 中调整向下滑动的距离?【英文标题】:How to adjust the swipe down distance in SwipeRefreshLayout? 【发布时间】:2014-05-16 09:50:53 【问题描述】:

我在我的应用中实现了 SwipeRefreshLayout。我需要更改必须向下滚动才能调用 onRefresh() 方法的高度。我应该使用哪种方法来添加自定义高度?

SwipeRefreshLayout的实现

private SwipeRefreshLayout swipeLayout;

在创建时

swipeLayout   = (SwipeRefreshLayout)view.findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
        swipeLayout.setColorScheme(android.R.color.holo_blue_dark, 
                android.R.color.holo_green_dark, 
                android.R.color.holo_purple, 
                android.R.color.holo_orange_dark);   
        swipeLayout.setSoundEffectsEnabled(true);

在onrefresh方法中实现一个AsyncTask

   @Override
public void onRefresh() 

    // Asynctask to perform some task  


【问题讨论】:

你真的应该分享你的代码 有人可以评论为什么这个问题被否决了吗? 在这里查看http://blog.xamarin.com/android-the-swipe-down-to-refresh-pattern/它可能对你有帮助 【参考方案1】:

v4 支持库的版本 21 提供了一个 API 来设置距离。

public void setDistanceToTriggerSync (int distance)

查看文档here。

还有一件事,转速。 21 更改了进度条的行为,现在是圆形图像。不知道如何恢复原来的方式。

【讨论】:

【参考方案2】:

如果您使用的是支持库的 API 21,请参考并点赞韩河的回答 here。存在一种设置触发距离的方法,称为setDistanceToTriggerSync


在 API 21 之前,正如 adneal 所提到的,没有公共或内部方法可以修改触发距离。

但是,如果您不想保留类的副本来修改常量,可以使用反射手动设置触发距离。

swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);

// define a distance
Float mDistanceToTriggerSync = yourCalculation(); 

try 
    // Set the internal trigger distance using reflection.
    Field field = SwipeRefreshLayout.class.getDeclaredField("mDistanceToTriggerSync");
    field.setAccessible(true);
    field.setFloat(swipeLayout, mDistanceToTriggerSync);
 catch (Exception e) 
    e.printStackTrace();

如果您使用布局的高度来确定距离,您可能需要使用GlobalLayoutListener 之类的东西。

mDistanceToTriggerSync

SwipeRefreshLayout 中,有一个名为mDistanceToTriggerSync 的内部变量。 这用于确定触发刷新的距离。

在源码中,由SwipeRefreshLayout中的下面代码设置:

final DisplayMetrics metrics = getResources().getDisplayMetrics();
mDistanceToTriggerSync = (int) Math.min(
        ((View) getParent()) .getHeight() * MAX_SWIPE_DISTANCE_FACTOR,
                REFRESH_TRIGGER_DISTANCE * metrics.density);

上面使用了父视图高度和一些常量来计算触发距离。 MAX_SWIPE_DISTANCE_FACTOR (0.6) 和 REFRESH_TRIGGER_DISTANCE (120) 是类中的私有常量,您无法修改。

您可以使用上述方法计算触发距离,并使用您自己的常数作为滑动距离因子。

全局布局监听器

mDistanceToTriggerSync 的设置可以在全局布局侦听器中完成,以便可以正确检索布局的高度以计算触发距离。在 onCreate 中的视图上调用 getHeight 将始终返回 0,因为它还没有被绘制。我从here 获得了代码。根据您的要求,您可能需要也可能不需要这样做。

ViewTreeObserver vto = swipeLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
    @Override
    public void onGlobalLayout() 
        // Calculate the trigger distance.
        final DisplayMetrics metrics = getResources().getDisplayMetrics();
        Float mDistanceToTriggerSync = Math.min(
                ((View) swipeLayout.getParent()).getHeight() * 0.6f,
                120 * metrics.density);

        try 
            // Set the internal trigger distance using reflection.
            Field field = SwipeRefreshLayout.class.getDeclaredField("mDistanceToTriggerSync");
            field.setAccessible(true);
            field.setFloat(swipeLayout, mDistanceToTriggerSync);
         catch (Exception e) 
            e.printStackTrace();
        

        // Only needs to be done once so remove listener.
        ViewTreeObserver obs = swipeLayout.getViewTreeObserver();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 
            obs.removeOnGlobalLayoutListener(this);
         else 
            obs.removeGlobalOnLayoutListener(this);
        
    
);

如果我正确理解底层代码,变量的设置只需要完成一次,因为它只设置mDistanceToTriggerSync,如果它等于-1。因此,在全局布局监听器中做一次应该是安全的。

SwipeRefreshLayout

如果您对SwipeRefreshLayout的源代码感兴趣,可以找到here。

【讨论】:

是的,除了在上面复制类之外,除了向 AOSP 提交补丁之外,实际上是唯一的其他解决方法。我们的每个答案都有其缺点,但我认为这是一个很好的答案。 @adneal 谢谢,是的,两者都有缺点,希望它在未来更加可定制,除非有这样的原因。 我在 Github 上创建了 gist,你可以从这里访问它:gist.github.com/bhaumiknsoni/77850b4369a1bd4a67ab 感谢singularhum 如果您使用反射方法,该字段现在称为“mTotalDragDistance”而不是“mDistanceToTriggerSync”。以防万一有人遇到这种情况。【参考方案3】:

目前还没有一个公开的方法,甚至没有一个内部的方法可以用来调整触发距离。但是您可以将支持库中的三个类复制到您的项目中,然后根据自己的喜好修改SwipeRefreshLayout

以下是您需要复制的类:

BakedBezierInterpolator SwipeProgressBar SwipeRefreshLayout

使用常数计算跳跳距离:

 private static final float MAX_SWIPE_DISTANCE_FACTOR = .6f;
 private static final int REFRESH_TRIGGER_DISTANCE = 120;

在您的布局中将 <android.support.v4.widget.SwipeRefreshLayout.../> 更改为 <your_path_to_SwipeRefreshLayout.../> 并确保您更改您的导入,如果需要的话。

【讨论】:

【参考方案4】:

这个只是做了一个技巧,没有更多的额外代码 只需将你的 recyclerview 包装到 NestedScrollView 然后这个 NestedScrollView 被包装在 SwipeRefreshLayout

检查下面的代码

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
     android:id="@+id/swipe_refresh_layout"
     android:layout_
     android:layout_>

     <androidx.core.widget.NestedScrollView
           android:layout_
           android:layout_>
           
           <androidx.recyclerview.widget.RecyclerView
                  android:id="@+id/recycler_view"
                  android:layout_
                  android:layout_ />

     </androidx.core.widget.NestedScrollView>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

【讨论】:

这是不好的做法。我不建议这样做

以上是关于如何在 SwipeRefreshLayout 中调整向下滑动的距离?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VBA 中调暗和设置变量工作簿名称?

如何在android中使用SwipeRefreshLayout和imageView进入NestedScrollView

android 如何将swiperefreshlayout刷新动画能定制吗

如何在Hue中调优Impala和Hive查询

如何在 Scene Kit 或 ARkit 中的 Camera 渲染的视图中调暗灯光?

android之官方下拉刷新组件SwipeRefreshLayout