CoordinatorLayout+AppBarLayout实现主流app首页效果

下面的recyclerview支持下拉刷新和加载更多,同时支持Tablayout滑动悬浮置顶,同时为了解决列表下拉刷新和AppBarLayout滚动视图滑动冲突,
发现有两种方案:
1,列表直接不支持下拉刷新,只支持加载更多
2,列表支持下拉刷新,但是需设置当AppBarLayout完全收缩时开启,在AppBarLayout展开时不能下拉刷新。

1,布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tl="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:orientation="vertical"
    tools:context="txkj.xian.com.txproject.activity.TestIndexActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/gray"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="标题栏搜索"
            android:textAlignment="center"
            android:textColor="@color/black_6"
            android:textSize="18sp" />
    </LinearLayout>

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/appBarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="0dp"
            app:layout_behavior="@string/no_scroll_behavior">

            <android.support.constraint.ConstraintLayout
                android:id="@+id/const_banner"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_scrollFlags="scroll">

                <com.youth.banner.Banner
                    android:id="@+id/banner"
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    app:banner_default_image="@drawable/default_image"
                    app:indicator_drawable_selected="@drawable/banner_indicator_select_color"
                    app:indicator_drawable_unselected="@drawable/banner_indicator_unselect_color"
                    app:indicator_height="5dp"
                    app:indicator_margin="2dp"
                    app:indicator_width="5dp"
                    app:layout_constraintDimensionRatio="h,720:326"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:title_textcolor="@color/white"
                    app:title_textsize="15sp" />

            </android.support.constraint.ConstraintLayout>

            <com.flyco.tablayout.SlidingTabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="@color/white"
                tl:tl_indicator_color="@color/newtitle"
                tl:tl_indicator_height="2dp"
                tl:tl_indicator_style="NORMAL"
                tl:tl_tab_space_equal="true"
                tl:tl_textSelectColor="@color/newtitle"
                tl:tl_textUnselectColor="@color/black_2"
                tl:tl_textsize="14sp" />

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

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        </android.support.v4.view.ViewPager>

    </android.support.design.widget.CoordinatorLayout>
</LinearLayout>
  • 上面借助ConstraintLayout约束布局实现Banner的宽高适配
  • 默认AppBarLayout中使用Tablayout时会有阴影,可通过给AppBarLayout设置app:elevation="0dp"去掉该阴影

2,AppBarLayout使用了自定义的behavior,用于控制appbar的滑动,代码如下:

public class NoScrollBehavior extends AppBarLayout.Behavior{

    public boolean noScroll;


    public NoScrollBehavior() {
    }

    public NoScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public boolean isNoScroll() {
        return noScroll;
    }

    public void setNoScroll(boolean noScroll) {
        this.noScroll = noScroll;
    }


    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
        if (noScroll) {
            return false;
        } else {
            return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
        }
    }
}

3,Activity中代码如下:

public class TestIndexActivity extends BaseActivity implements AppBarLayout.OnOffsetChangedListener {

    @BindView(R.id.banner)
    Banner banner;
    @BindView(R.id.tabLayout)
    SlidingTabLayout tabLayout;
    @BindView(R.id.viewpager)
    ViewPager viewPager;
    @BindView(R.id.appBarLayout)
    AppBarLayout appBarLayout;
    @BindView(R.id.textView)
    TextView textView;

    private boolean isAlreadyInit;
    private List<BaseLazyLoadFragment> mFagments = new ArrayList<>();
    private String[] mTitles = new String[]{"推荐","精选"};

    private NoScrollBehavior myAppBarLayoutBehavoir;  // 自定义的 behavior 用于控制appbar的滑动

    private ZixunFragment2 currentFragment;

    @Override
    public int setLayout() {
        return R.layout.activity_test_index;
    }


    @Override
    public void initView() {

        myAppBarLayoutBehavoir = (NoScrollBehavior)
                ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior();

        // 获取顶部banner数据
        getBannerData();
        mFagments.add(ZixunFragment2.getInstance("1"));
        mFagments.add(ZixunFragment2.getInstance("2"));
        MyAdapter adapter = new MyAdapter(getSupportFragmentManager(), mFagments);
        viewPager.setAdapter(adapter);
        // 设置标题选项
        tabLayout.setViewPager(viewPager, mTitles);
        currentFragment = (ZixunFragment2) mFagments.get(0);
    }

    @Override
    protected void setListener() {
        appBarLayout.addOnOffsetChangedListener(this);
        tabLayout.setOnTabSelectListener(new OnTabSelectListener() {
            @Override
            public void onTabSelect(int position) {
                currentFragment = (ZixunFragment2) mFagments.get(position);
            }

            @Override
            public void onTabReselect(int position) {

            }
        });
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                currentFragment = (ZixunFragment2) mFagments.get(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //返回监听 当appBar处于不可滑动(即完全折叠)时,先释放appBar
                if (myAppBarLayoutBehavoir.isNoScroll()) {
                    myAppBarLayoutBehavoir.setNoScroll(false);
                    // 设置appbar展开
                    appBarLayout.setExpanded(true, true);
                } else {
//                    mSwipeBackHelper.backward();
                }
            }
        });
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
        //顶部渐变 标题栏处理  滑动竖直距离/appBarLayout滚动区域的总高度 值变化范围:0~1
        float percent = Float.valueOf(Math.abs(verticalOffset)) / Float.valueOf(appBarLayout.getTotalScrollRange());
        // 滑动事件处理
        if (percent == 0) {
            // 为0代表没有滑动,即完全展开时  appbar可滑动  禁止refresh(可根据需求不禁止刷新)
            myAppBarLayoutBehavoir.setNoScroll(false);
            currentFragment.setRefreshState(false);
        } else if (percent == 1) {
            //为1代表完全折叠  appbar不可滑动使tab吸顶   允许refresh
            currentFragment.setRefreshState(true);
            myAppBarLayoutBehavoir.setNoScroll(true);
        } else {
            // 滑动中,介于0和1之间 appbar可滑动 禁止refresh(建议禁止刷新,否则会appbar影响滑动流畅)
            myAppBarLayoutBehavoir.setNoScroll(false);
            currentFragment.setRefreshState(false);
        }
    }

    public class MyAdapter extends FragmentPagerAdapter {

        private final List<BaseLazyLoadFragment> mFagments;

        public MyAdapter(FragmentManager fm, List<BaseLazyLoadFragment> mFagments) {
            super(fm);
            this.mFagments = mFagments;
        }

        @Override
        public Fragment getItem(int position) {
            return mFagments.get(position);
        }

        @Override
        public int getCount() {
            return mFagments.size();
        }
    }

    // 参数表示是不是更新
    private void getBannerData() {
        OkGo.<ResponseResult<HomeBanner>>get(UrlConstant.GET_BANNER)
                .tag(this)
                .execute(new JsonCallback<ResponseResult<HomeBanner>>() {
                    @Override
                    public void onSuccess(Response<ResponseResult<HomeBanner>> response) {
                        ResponseResult<HomeBanner> body = response.body();
                        int code = body.getCode();
                        if (code == 200) {

                            if(!isAlreadyInit){
                                List<String> images = new ArrayList<>();
                                List<HomeBanner.BannerBean> banner2 = body.getData().getBanner();
                                for (HomeBanner.BannerBean hb : banner2) {
                                    images.add(hb.getImgUrl());
                                }
                                initBanner(images);
                                isAlreadyInit = true;
                            }

                        } else {
                            // banner数据获取失败
                        }
                    }
                });
    }

    // 顶部Banner轮播
    private void initBanner(List<String> images) {
        if (banner != null) {
            //设置banner样式
            banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);
            //设置图片加载器
            banner.setImageLoader(new GlideImageLoader());
            //设置图片集合
            banner.setImages(images);
            //设置banner动画效果
            banner.setBannerAnimation(Transformer.Default);
            //设置标题集合(当banner样式有显示title时)
//        banner.setBannerTitles(titles);
            //设置自动轮播,默认为true
            banner.isAutoPlay(true);
            //设置轮播时间
            banner.setDelayTime(5000);
            //设置指示器位置(当banner模式中有指示器时)
            banner.setIndicatorGravity(BannerConfig.CENTER);

            //banner设置方法全部调用完毕时最后调用
            banner.setOnBannerListener(new OnBannerListener() {
                @Override
                public void OnBannerClick(int position) {
                    Toast.makeText(TestIndexActivity.this, "点击"+position, Toast.LENGTH_SHORT).show();
                }
            });
            banner.start();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        appBarLayout.removeOnOffsetChangedListener(this);  // 解除监听
    }

}

其余的就是定义fragment,实现不同的列表,需要注意的是在fragment中需要提供一个可以设置开启和关闭下拉刷新的方法,如下:

public void setRefreshState(boolean b) {
        refreshLayout.setEnabled(b);
    }

以上主要使用到的第三方开源库包括:
1,Banner轮播图:com.youth.banner:banner:1.4.10
2,TabLayout选项切换:FlycoTabLayout_Lib
3,下拉刷新:SmartRefreshLayout
4,RecycleView:BaseRecyclerViewAdapterHelper
5,不同状态(无网络,无数据等)视图切换库:com.ganxin.library:loaddatalayout:1.0.1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智玲君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值