草庐IT

android - 在 android 中快速滚动时避免滑动刷新

coder 2023-12-03 原文

我有一个 ListView 始终启用 fastScrollSwipeRefresh 实现。当我向下滑动列表时,它会刷新列表。我的问题是 fastScroll。如果列表的第一个项目可见或位于初始顶部,则如果向下滚动 fastScrollThumb,它会产生 Swipe 效果,而不是向下滚动。无论如何/解决方案,如果我按下 fastScrollThumb ,那么它不应该做 Swipe 刷新效果,而是应该向下滚 Action 为它的自然行为。

已编辑 我的 XML 布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.SwipeRefreshLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <RelativeLayout
            android:id="@+id/buttons_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"> 

            <ImageView
                android:id="@+id/SubmitButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/neoo_tab_selector" />

        </RelativeLayout>


        <ListView
            android:id="@id/android:list"
            style="@style/NeeoContactListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/buttons_layout"
            android:layout_marginTop="10dp" />
    </RelativeLayout>

</android.support.v4.widget.SwipeRefreshLayout>

我用于启用/禁用 SwipeRefreshonScroll 逻辑 是:

    getListView().setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        boolean enable = false;
        if(getListView() != null && getListView().getChildCount() > 0){
            // check if the first item of the list is visible
            boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
            // check if the top of the first item is visible
            boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
            // enabling or disabling the refresh layout
            enable = firstItemVisible && topOfFirstItemVisible;
        }
        if(enable){
            enableSwipe();

        }else{
            disableSwipe();

        }
    }
});

最佳答案

我刚刚查看了 the documentation SwipeRefreshLayout 的,我认为他们提到了您正在寻找的内容:

... If the listener determines there should not be a refresh, it must call setRefreshing(false) to cancel any visual indication of a refresh. If an activity wishes to show just the progress animation, it should call setRefreshing(true). To disable the gesture and progress animation, call setEnabled(false) on the view.

所以你有几个选择,我会首先尝试使用 setEnabled()setRefreshing(),但要正确使用这些方法,我们首先需要能够检测 ListView 是否正在快速滚动。没有用于快速滚动的监听器或任何东西,但您可以通过反射获取状态!基于this excellent and seriously underrated answer我写了一个 FastScrollListener,它可以像 OnScrollListener 一样使用:

this.listView.setFastScrollEnabled(true);
this.listView.setOnScrollListener(new FastScrollListener(this.listView) {

    @Override
    protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
        // This line disabled the SwipeRefreshLayout  
        // whenever the user is fast scrolling
        swipeRefreshLayout.setEnabled(state != FastScrollState.DRAGGING);
    }

    @Override
    protected void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
});

如果 setEnabled() 不起作用,您也可以尝试调用 setRefreshing() 而不是 setEnabled()

这里是FastScrollListener的代码:

public abstract class FastScrollListener implements AbsListView.OnScrollListener {

    private final int STATE_DRAGGING;
    private final int STATE_VISIBLE;
    private final int STATE_NONE;

    public enum FastScrollState {
        DRAGGING,
        VISIBLE,
        NONE,
        UNKNOWN
    }

    private FastScrollState fastScrollState = FastScrollState.UNKNOWN;
    private Field stateField;
    private Object mFastScroller;

    public FastScrollListener(AbsListView listView) {
        try {
            final Field fastScrollerField = AbsListView.class.getDeclaredField("mFastScroller");
            fastScrollerField.setAccessible(true);
            mFastScroller = fastScrollerField.get(listView);

            final Field stateDraggingField = mFastScroller.getClass().getDeclaredField("STATE_DRAGGING");
            stateDraggingField.setAccessible(true);
            STATE_DRAGGING = stateDraggingField.getInt(mFastScroller);

            final Field stateVisibleField = mFastScroller.getClass().getDeclaredField("STATE_VISIBLE");
            stateVisibleField.setAccessible(true);
            STATE_VISIBLE = stateVisibleField.getInt(mFastScroller);

            final Field stateNoneField = mFastScroller.getClass().getDeclaredField("STATE_NONE");
            stateNoneField.setAccessible(true);
            STATE_NONE = stateNoneField.getInt(mFastScroller);

            stateField = mFastScroller.getClass().getDeclaredField("mState");
            stateField.setAccessible(true);
            fastScrollState = getFastScrollState();

        } catch (NoSuchFieldException e) {
            throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        updateFastScrollState(view);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        updateFastScrollState(view);
        updateFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
    }

    private void updateFastScrollState(AbsListView view) {
        if (stateField != null) {
            final FastScrollState state = getFastScrollState();
            if (fastScrollState != state) {
                fastScrollState = state;
                onFastScrollStateChanged(view, state);
            }
        }
    }

    private void updateFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if(fastScrollState == FastScrollState.DRAGGING) {
            onFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    private FastScrollState getFastScrollState() {

        try {
            final int state = stateField.getInt(mFastScroller);

            if (state == STATE_DRAGGING) {
                return FastScrollState.DRAGGING;
            }

            if (state == STATE_VISIBLE) {
                return FastScrollState.VISIBLE;
            }

            if (state == STATE_NONE) {
                return FastScrollState.NONE;
            }

            return FastScrollState.UNKNOWN;
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Could not read fast scroll state!", e);
        }
    }

    protected abstract void onFastScrollStateChanged(AbsListView view, FastScrollState state);

    protected abstract void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount);
}

希望能帮到您,如果您还有其他问题,请随时提问!


编辑:试试这个,但我怀疑它是否有效:

@Override
protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
    boolean enable = false;
    if (getListView().getChildCount() > 0) {
        boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
        boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
        enable = firstItemVisible && topOfFirstItemVisible;
    }
    refreshLayout.setEnabled(enable);
}

关于android - 在 android 中快速滚动时避免滑动刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24863038/

有关android - 在 android 中快速滚动时避免滑动刷新的更多相关文章

  1. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  2. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  3. ruby - 如何以表格格式快速打印 Ruby 哈希值? - 2

    有没有办法快速将表格格式的ruby​​哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:

  4. 电脑启动后显示器黑屏怎么办?排查下面4个问题,快速解决 - 2

    电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑

  5. ruby - 在 Ruby 中为变量赋值时如何避免控制台输出 - 2

    赋值时是否可以避免这种影响:irb(main):584:0>a=true=>trueirb(main):584:0>我有一个代码有很多赋值,当我试图测试它时,由于所有这些返回值,我看不到结果:truefalsetruefalsetruetrue.. 最佳答案 您可以启动irb或附加--noecho选项的控制台。$irb--noecho2.0.0p353:001>true2.0.0p353:002>否则,如果控制台由另一个进程启动,只需设置conf.echo=false$irb2.0.0p353:001>true=>true2.0.0

  6. ruby-on-rails - Rails - 如何避免在 View 中使用 hidden_​​fields 将值传递给 Controller ​​? - 2

    有没有一种方法可以避免hidden_​​field方法将View中的值传递给Controller​​?出于安全原因,我更喜欢Controller方法。不幸的是,strong_parameters不支持值对@variables。EDIT6/181:00PMESTI'verenamedmygaragescontrollertoappointmentscars_controllernolongercreatesanewappointment(formallygarages).Anewappointmentiscreatedintheappointments_controller我目前的结构路

  7. ruby - 使单元测试快速失败以进行突变测试 - 2

    mutationtesting遇到一个问题是它很慢,因为默认情况下您会为每个生成的突变执行完整的测试运行(测试文件或一组测试文件)。加快突变测试的一种方法是,一旦遇到单一故障(但仅在突变测试期间),就停止对给定突变体的测试运行。更好的做法是让变异测试者记住杀死最后一个变异体的第一个测试是什么,并将其首先交给下一个变异体。ruby中是否有任何东西可以做这些事情,或者我最好的选择是开始猴子修补?(是的,我知道单元测试应该很快。显示所有失败的测试在突变测试之外很有用,因为它不仅可以帮助您识别出问题,还可以查明哪里出了问题)编辑:我目前正在对测试/单元使用heckle。如果测试/单元不可能记住

  8. ruby - 如何使用 ruby​​ fibers 避免阻塞 IO - 2

    我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文

  9. ruby - 有没有办法将 html 刷新到 Sinatra 中的线路 - 2

    我有一个Sinatra应用程序,它有一个长时间运行的进程(网络抓取工具)。我希望应用程序在爬虫运行时而不是在结束时刷新爬虫进度的结果。我已经考虑过fork请求并使用ajax做一些有趣的事情,但这是一个非常基本的单页应用程序,实际上只需要在它发生时将日志输出到浏览器。有什么建议吗? 最佳答案 更新(2012-03-21)从Sinatra1.3.0开始,您可以使用新的流式API:get'/'dostreamdo|out|out旧答案不幸的是,您没有可以简单地刷新到的流(这不适用于Rack中间件)。从路由block返回的结果可以简单地响应

  10. ruby - 使用和不使用 Rails 的快速 (Rspec) 测试 - 2

    我有两个类:1.Sale是ActiveRecord的子类;它的工作是将销售数据持久保存到数据库中。classSale2.SalesReport是一个标准的Ruby类;它的工作是生成和绘制有关销售的信息。classSalesReportdefinitialize(start_date,end_date)@start_date=start_date@end_date=end_dateenddefsales_in_durationSale.total_for_duration(@start_date,@end_date)end#...end因为我想使用TDD并且我希望我的测试运行得非常快,所

随机推荐