SwipeToLoadLayout icon indicating copy to clipboard operation
SwipeToLoadLayout copied to clipboard

请教个 CoordinatorLayout 和 AppBarLayout 提早下拉刷新的问题

Open tsunamilx opened this issue 9 years ago • 10 comments

先看布局

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".android.core.activities.MainActivity">

        <include layout="@layout/include_app_bar_layout"/>

        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        </FrameLayout>

    </android.support.design.widget.CoordinatorLayout>

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

上面 <include layout="@layout/include_app_bar_layout"/> 就是下面的 AppBarLayout。 中间的 FrameLayout 是主内容,是给Fragment的,Fragment的布局就是你的SwipeToLoadLayout

AppBarLayout

<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/toolbar_height"
        android:layout_gravity="center"
        android:layout_marginEnd="@dimen/toolbar_margin"
        android:layout_marginLeft="@dimen/toolbar_margin"
        android:layout_marginRight="@dimen/toolbar_margin"
        android:layout_marginStart="@dimen/toolbar_margin"
        android:paddingTop="@dimen/toolbar_padding_top_basic"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/AppTheme.PopupOverlay">

        <include layout="@layout/include_toolbar_basic_light"/>
        <include layout="@layout/include_toolbar_basic_dark"/>

    </android.support.v7.widget.Toolbar>

</android.support.design.widget.AppBarLayout>

SwipeToLoadLayout

<com.aspsine.swipetoloadlayout.SwipeToLoadLayout
    android:id="@+id/refresh_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--
    Don't add anything nor change the view id, SwipeToLoadLayout hard coded
    the view id, and only accept max 3 child views.
    -->

    <cn.com.cityweekend.android.utils.views.RefreshHeaderView
        android:id="@+id/swipe_refresh_header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:indicator_color="@color/colorPrimary"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/swipe_target"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"/>

    <cn.com.cityweekend.android.utils.views.LoadMoreFooterView
        android:id="@+id/swipe_load_more_footer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:indicator_color="@color/colorPrimary"/>

</com.aspsine.swipetoloadlayout.SwipeToLoadLayout>

再看截图 这是初始状态 screenshot_20160602-231022

上面蓝色区域整个都是 AppBarLayout,里面就是自己加了几个image和button。 蓝色区域下面就是你的SwipeToLoadLayout。

初始状态下下拉当然是没有问题的,如下图 screenshot_20160602-231013

当屏幕往上滚动的时候,AppBarLayout 整个会一起滚上去,然后往下滚动的时候,AppBarLayout 会马上出现,等 AppBarLayout 全部出现后,然后列表(RecyclerView)才开始滚动,这是 CoordinatorLayout 和 AppBarLayout 组合的效果。 问题就在于,如果滚动状态停在 AppBarLayout 出现一半的时间,松手,然后在往下滚动的时候,会出现下拉刷新,如下图 screenshot_20160602-231035

这样 AppBarLayout 就显示不全了,必须要先往上滚动一下,不松手,再往下滚动,就是正常的效果。

这就是我所谓的“提早下拉刷新的问题”,我稍后录个频帮助理解。

tsunamilx avatar Jun 02 '16 15:06 tsunamilx

意思是,当AppbarLayout处于缩起状态时,下拉先让其展开,完全展开后再触发刷新吧?

Aspsine avatar Jun 03 '16 01:06 Aspsine

对是的

tsunamilx avatar Jun 03 '16 01:06 tsunamilx

录屏在此 record

tsunamilx avatar Jun 03 '16 03:06 tsunamilx

请问有什么进展吗

tsunamilx avatar Jun 06 '16 10:06 tsunamilx

@tsunamilx 抱歉,最近比较忙,你可以先尝试自己修复一下。

Aspsine avatar Jun 07 '16 10:06 Aspsine

@tsunamilx 我也遇到这问题,临时找到个解决办法,你可以试试 @Aspsine 作者有没有计划解决这个问题 🙏🙏🙏🙏🙏

public class MainHomeFragment extends BaseFragment implements AppBarLayout.OnOffsetChangedListener{

    @Bind(R.id.app_bar_layout)
    AppBarLayout app_bar_layout;
    @Bind(R.id.swipeToLoadView)
    SwipeToLoadView swipeToLoadView;

    private void initDisplay() {
        app_bar_layout.addOnOffsetChangedListener(this);
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        // i == 0 就代表AppBarLayout展开了
        if (!swipeToLoadView.isRefreshing()) 
            swipeToLoadView.setRefreshEnabled(i==0);
    }
}

binglingziyu avatar Aug 22 '16 10:08 binglingziyu

让子Fragment实现接口SwipeChildListener

public interface SwipeChildListener {

    /**
     * 启用下拉刷新功能
     *
     * @see SwipeLayout#enableRefresh()
     */
    void enableRefresh();

    /**
     * 禁用下拉刷新功能
     *
     * @see SwipeLayout#disableRefresh()
     */
    void disableRefresh();
}

然后在添加AppBarLayout滚动的监听事件

 // 监听头部滚动状态
 mAppBarLayout.addOnOffsetChangedListener(this);
 @Override
 public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
        float alpha = (appBarLayout.getTotalScrollRange() + verticalOffset) * 1.0f / appBarLayout.getTotalScrollRange();

        // 全面展开状态,在一定范围内
        boolean fullExpanded = verticalOffset > -10;

        Fragment fragment = mAdapter.mFragmentList.get(mPager.getCurrentItem());
        if (fragment != null && fragment instanceof SwipeChildListener) {
            SwipeChildListener listener = (SwipeChildListener) fragment;
            // 只有在全面展开状态时才允许子页面开启刷新功能以防止手势冲突
            if (fullExpanded) {
                listener.enableRefresh();
            } else {
                listener.disableRefresh();
            }
        }
 }

子Fragment实现接口方法:

 @Override
    public void enableRefresh() {
        mSwipeLayout.setRefreshEnabled(true);;
    }

    @Override
    public void disableRefresh() {
        mSwipeLayout.setRefreshEnabled(false);
    }

act262 avatar Aug 25 '16 02:08 act262

还是你们厉害,我是直接修改了SwipeToLoadLayout,把Toolbar塞进了SwipeToLoadLayout里面,然后在onCheckCanRefresh()方法里判断了Toolbar的可见高度来判定是否开始刷新。

tsunamilx avatar Aug 25 '16 02:08 tsunamilx

@act262 还需要再接口中补充一个isRefreshing的方法,否则在刷新状态时,往上轻轻一推,refresh header会收不回去

public interface SwipeChildListener {

    boolean isRefreshing();

    void enableRefresh();

    void disableRefresh();
}
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                float alpha = (appBarLayout.getTotalScrollRange() + verticalOffset) * 1.0f / appBarLayout.getTotalScrollRange();
                if(!swipeChildListener.isRefreshing()){
                    // 全面展开状态,在一定范围内
                    boolean fullExpanded = verticalOffset > -10;

                    // 只有在全面展开状态时才允许子页面开启刷新功能以防止手势冲突
                    if (fullExpanded) {
                        swipeChildListener.enableRefresh();
                    } else {
                        swipeChildListener.disableRefresh();
                    }
                }
            }
        });

robinxdroid avatar Sep 23 '16 04:09 robinxdroid

是的,还有加载footer的2个方法也需要放到接口处理一下,可以处理子页面内容在没有充满父布局导致的问题

act262 avatar Sep 23 '16 06:09 act262