Android实现标题吸顶+双表头锁(表头吸顶)功能

一、产品需求,2功能切换,一个标题吸顶+双锁表头上滑动也实现表格头部吸顶功能。所以记录一下实现过程。

最终效果如下GIF图:(1)第一个吸顶标题按日、按月吸顶(2)第二个吸顶切换到表格数据之后,上滑,表格第一行吸顶。

好了,效果看完,来简单说下具体实现思路。

1.此需求重点麻烦在表格吸顶,双锁头这个模块上。左边日月标题吸顶这个简单可以实现。

CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+NestedScrollView就可以了

2.难点就在双表头锁,刚刚开始,有想过用CoordinatorLayout+ListView来实现 ,并且带横向滑动布局,后面实现出来之后,发觉,CoordinatorLayout和ListView有上下滑动冲突,当ListView控件显示的时候,外层吸顶就不可滑动,类似就是滑动时间冲突。后面实在没办法,选择用动态绘制View来进行实现。虽然从效率还说肯定没有listview控件好,也试着去自定义了ListView控件,还是没有得到满意的效果。

二、代码实现

1.总体xml布局

<LinearLayout 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:background="@color/color_F0F1F6"
    android:clipToPadding="false"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <com.eeepay.eeepay_v2.ui.view.TitleBar
        android:id="@+id/titlebar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/title_bar_height"
        app:centreTitle="数据"
        app:showLeft="false" />

    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#70FFFFFF"
        app:srlAccentColor="#70FFFFFF"
        app:srlEnablePreviewInEditMode="true"
        app:srlPrimaryColor="@color/unify_bg">

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

            <android.support.design.widget.AppBarLayout
                android:id="@+id/app_bar_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fadingEdge="none"
                android:orientation="vertical"
                app:elevation="0dp"
                app:layout_behavior="com.eeepay.eeepay_v2.ui.view.AppBarLayoutBehavior">

                <android.support.design.widget.CollapsingToolbarLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_scrollFlags="scroll|exitUntilCollapsed"
                    app:statusBarScrim="@android:color/transparent">

                    <!-- 滑动时隐藏此段布局 -->
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@color/white"
                        android:visibility="visible">

                        <!--我的累计收益(元)-->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="vertical"
                            android:visibility="visible">

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

                        </LinearLayout>

                        <!--本月业绩-->
                        <LinearLayout
                            android:id="@+id/ll_thismonth"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="200dp"
                            android:orientation="vertical"
                            android:visibility="visible">

                            <com.dd.ShadowLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_marginLeft="@dimen/size_6"
                                android:layout_marginRight="@dimen/size_6"
                                android:layout_weight="1"
                                android:background="@color/white"
                                android:padding="@dimen/size_1"
                                app:sl_cornerRadius="6dp"
                                app:sl_dx="0dp"
                                app:sl_dy="0dp"
                                app:sl_shadowColor="#26f0f1f6"
                                app:sl_shadowRadius="6dp">

                                <LinearLayout
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content"
                                    android:background="@drawable/bg_data_round_white"
                                    android:orientation="vertical"
                                    android:paddingLeft="15dp"
                                    android:paddingRight="15dp"
                                    android:paddingBottom="5dp">

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

                                </LinearLayout>
                            </com.dd.ShadowLayout>
                        </LinearLayout>


                        <!--我的机具-->
                        <LinearLayout
                            android:id="@+id/ll_my_dev"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/ll_thismonth"
                            android:layout_marginTop="@dimen/size_15"
                            android:orientation="vertical"
                            android:visibility="visible">

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

                        </LinearLayout>

                        <!--数据分析-->
                        <LinearLayout
                            android:id="@+id/ll_analysis_title"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/ll_my_dev"
                            android:orientation="vertical"
                            android:visibility="visible">

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

                        </LinearLayout>

                        <!--团队排名标题-->
                        <TextView
                            android:id="@+id/tv_top_count_num"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/ll_analysis_title"
                            android:layout_marginLeft="@dimen/size_20"
                            android:layout_marginBottom="@dimen/size_20"
                            android:text="团队排名"
                            android:textColor="@color/color_48526A"
                            android:textSize="@dimen/textSize_15sp"
                            android:textStyle="bold"
                            android:visibility="gone" />

                    </RelativeLayout>

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

                <!--吸顶布局-->
                <LinearLayout
                    android:id="@+id/ll_trend_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:visibility="visible">
                    <!-- 趋势图title吸顶,模块布局 -->
                    <include layout="@layout/fragment_data_opt_trend_title" />

                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_rankinglist_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/white"
                    android:orientation="vertical"
                    android:paddingLeft="@dimen/size_20"
                    android:paddingRight="@dimen/size_20"
                    android:visibility="gone">
                    <!-- 趋排行榜title吸顶,模块布局 -->
                    <include layout="@layout/fragment_data_opt_rankinglist_title" />

                </LinearLayout>


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

            <!-- 也可以嵌套NestedScrollView 或其他父布局。同时加上这个属性:app:layout_behavior -->
            <android.support.v4.widget.NestedScrollView
                android:id="@+id/nested_scrolview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_behavior="@string/appbar_scrolling_view_behavior">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/white"
                    android:orientation="vertical"
                    android:paddingLeft="@dimen/size_20"
                    android:paddingRight="@dimen/size_20">

                    <!--数据分析趋势图引入 2021年7月14日 12:36:42 liangan-->
                    <LinearLayout
                        android:id="@+id/ll_mines_include_trend"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/size_10"
                        android:orientation="vertical"
                        android:visibility="visible">

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

                    </LinearLayout>

                    <!--数据分析排行榜引入 2021年7月14日 12:36:42 liangan-->
                    <LinearLayout
                        android:id="@+id/ll_mines_include_ranking_list"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@color/white"
                        android:orientation="vertical"
                        android:visibility="gone">

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

                    </LinearLayout>

                </LinearLayout>

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

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

    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

</LinearLayout>

2.双吸顶title布局

按日按月fragment_data_opt_trend_title.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_data_opt_mines_trend"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:orientation="vertical">

    <!--模拟测试折线图控件标题 2021年7月14日 12:36:42 liangan-->
    <RelativeLayout
        android:id="@+id/rl_top_count_num"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center_vertical">

        <LinearLayout
            android:id="@+id/ll_select_day_month"
            android:layout_width="150dp"
            android:layout_height="@dimen/size_28"
            android:layout_centerInParent="true"
            android:background="@mipmap/btn_bg_blur_lef">

            <TextView
                android:id="@+id/tv_an_day"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="按日"
                android:textColor="@color/white"
                android:textSize="@dimen/textSize_13sp" />

            <TextView
                android:id="@+id/tv_an_month"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="按月"
                android:textColor="@color/black_color_363636"
                android:textSize="@dimen/textSize_13sp" />
        </LinearLayout>

    </RelativeLayout>


</LinearLayout>

标题头部fragment_data_opt_rankinglist_title.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_data_opt_mines_trend"
    android:layout_width="match_parent"
    android:layout_height="45dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_firstcolumn"
        android:layout_width="75dp"
        android:layout_height="match_parent"
        android:ellipsize="end"
        android:gravity="center"
        android:singleLine="true"
        android:text="表格头部"
        android:textColor="@color/color_48526A"
        android:textSize="@dimen/textSize_13sp" />

    <!--排行榜控件标题 2021年7月14日 12:36:42 liangan-->
    <com.eeepay.eeepay_v2.ui.view.HListViewScrollView
        android:id="@+id/h_scrollview_ranking_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:scrollbars="none">

        <LinearLayout
            android:id="@+id/ll_firstcolumn_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="horizontal">


        </LinearLayout>
    </com.eeepay.eeepay_v2.ui.view.HListViewScrollView>

</LinearLayout>

3.表格布局fragment_data_opt_rankinglist_table.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_data_opt_mines_trend"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white">

    <LinearLayout
        android:id="@+id/ll_top_table"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="horizontal">

        <!--表格内容第一列数据-->
        <LinearLayout
            android:id="@+id/ll_firstcolumn_table_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="vertical">

        </LinearLayout>

        <!--表格内容第二列数据开始,可左侧滑动-->
        <com.eeepay.eeepay_v2.ui.view.HListViewScrollView
            android:id="@+id/h_scrollview_ranking_table"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none">

            <LinearLayout
                android:id="@+id/ll_table_content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:orientation="vertical">

            </LinearLayout>

        </com.eeepay.eeepay_v2.ui.view.HListViewScrollView>

    </LinearLayout>

    <TextView
        android:id="@+id/tv_data_more"
        android:layout_width="match_parent"
        android:layout_height="@dimen/size_30"
        android:layout_below="@+id/ll_top_table"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:text="查看更多"
        android:textColor="@color/unify_text_color17" />
</RelativeLayout>

4.自定义横向锁头表控件(Android中多个HorizontalScrollView联动),表头第一行和表内容使用

public class HListViewScrollView extends HorizontalScrollView {

    public HListViewScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


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

    public HListViewScrollView(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        //当当前的HListViewScrollView被触摸时,滑动其它
        if (null != this.listener) {
            listener.onUIScrollChanged(l, t, oldl, oldt);
        } else {
            super.onScrollChanged(l, t, oldl, oldt);
        }
    }

    private ScrollChangedListener listener;

    public void setScrollChangedListener(ScrollChangedListener listener) {
        this.listener = listener;
    }

    /**
     * 同步监听所有HListViewScrollView
     */
    public interface ScrollChangedListener {
        public void onUIScrollChanged(int l, int t, int oldl, int oldt);
    }
}

5.代码实现模块,代码类中实现滑动监听,一下代码只挑选出用到的,需要实现各位老铁看着自定义代码就行了。大概的思路就这样。

public class DataOptFragments extends BaseMvpFragment implements HListViewScrollView.ScrollChangedListener {

    //TODO 标题水平滑动代码模块
    @BindView(R.id.h_scrollview_ranking_title)
    HListViewScrollView h_scrollview_ranking_title;

    //TODO 内容表格模块代码
    @BindView(R.id.h_scrollview_ranking_table)
    HListViewScrollView h_scrollview_ranking_table;


    //同步添加滑动监听事件
    h_scrollview_ranking_title.setScrollChangedListener(this);
    h_scrollview_ranking_table.setScrollChangedListener(this);

    /**
     * HListViewScrollView同步滑动设置
     *
     * @param l
     * @param t
     * @param oldl
     * @param oldt
     */
    @Override
    public void onUIScrollChanged(int l, int t, int oldl, int oldt) {
        h_scrollview_ranking_title.smoothScrollTo(l, t);
        h_scrollview_ranking_table.smoothScrollTo(l, t);
    }


//下面是动态绘制表格内容代码
    /**
     * 头部标题数据动态添加
     *
     * @param titleData
     */
    private void initTableTitles(ArrayList<String> titleData) {
        tv_firstcolumn.setText(titleData.get(0));//设置表格第一个数据
        tv_firstcolumn.setBackgroundColor(mContext.getResources().getColor(R.color.color_F0F1F6));
        for (int i = 1; i < titleData.size(); i++) {
            View viewTitle = LayoutInflater.from(mContext).inflate(R.layout.forecast_child_item, ll_firstcolumn_title, false);
            TextView tv_name_child = (TextView) viewTitle.findViewById(R.id.tv_name_child);
            tv_name_child.setBackgroundColor(mContext.getResources().getColor(R.color.color_F0F1F6));
            tv_name_child.setText(titleData.get(i));
            ll_firstcolumn_title.addView(viewTitle);
        }
    }

    /**
     * 内容数据动态添加
     *
     * @param tableContentData
     */
    private void initTableContent(ArrayList<ArrayList<String>> tableContentData) {
        //TODO 表格第一列数据加载
        for (int i = 0; i < tableContentData.size(); i++) {
            View firstcolumn_view = LayoutInflater.from(mContext).inflate(R.layout.forecast_child_item, ll_firstcolumn_table_content, false);
            TextView tv_name_child = firstcolumn_view.findViewById(R.id.tv_name_child);
            tv_name_child.setText(tableContentData.get(i).get(0));
            ll_firstcolumn_table_content.addView(firstcolumn_view);
        }

        //TODO 第一个for循环是看有多少行
        for (int i = 0; i < tableContentData.size(); i++) {
            View firstcolumn_views = LayoutInflater.from(mContext).inflate(R.layout.forecast_child_layout, ll_table_content, false);
            LinearLayout ll_name_child = firstcolumn_views.findViewById(R.id.ll_name_child);
            //TODO 第而个for循环是每一换行有多少列数据
            List<String> column_row_list = tableContentData.get(i);
            //TODO 第一列在上面已经单独加载(tableContentData.get(i).get(0)),所以这里从1开始
            for (int j = 1; j < column_row_list.size(); j++) {
                View viewContent = LayoutInflater.from(mContext).inflate(R.layout.forecast_child_item, ll_name_child, false);
                TextView tv_name_child = viewContent.findViewById(R.id.tv_name_child);
                tv_name_child.setText(column_row_list.get(j));
                ll_name_child.addView(viewContent);
            }
            ll_table_content.addView(firstcolumn_views);
        }
    }

    /**
     * 清空表格数据
     */
    public void cleanTableView() {
        ll_firstcolumn_table_content.removeAllViews();
        ll_table_content.removeAllViews();
    }

}

6.forecast_child_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_name_child"
        android:layout_width="75dp"
        android:layout_height="45dp"
        android:background="@drawable/forecast_child_item_bottom_bg"
        android:ellipsize="end"
        android:gravity="center"
        android:singleLine="true"
        android:text="一期"
        android:textColor="@color/color_48526A"
        android:textSize="@dimen/textSize_13sp" />

</LinearLayout>

7.forecast_child_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:orientation="vertical">

    <!--表格每一行的数据、里面再横向填充textview-->
    <LinearLayout
        android:id="@+id/ll_name_child"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">


    </LinearLayout>

</LinearLayout>

基本上就这些主要模块代码,如果有另外更实现想法思路的同学,可以留言交流完善。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现RecyclerView悬浮吸顶效果,可以使用以下步骤: 1. 创建一个布局文件,包含两个部分:一个用于悬浮显示的视图,一个用于RecyclerView。 2. 在Activity或Fragment中,找到RecyclerView并设置布局管理器和适配器。 3. 创建一个自定义的RecyclerView.ItemDecoration类,用于绘制悬浮视图。 4. 在自定义的ItemDecoration类中,重写getItemOffsets()方法,在该方法中计算悬浮视图的高度,并将其应用到RecyclerView的第一个可见项之上。 5. 在自定义的ItemDecoration类中,重写onDraw()方法,在该方法中绘制悬浮视图。 6. 在Activity或Fragment中,为RecyclerView添加ItemDecoration。 下面是一个简单的示例代码: 1. 创建布局文件(例如:activity_main.xml): ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/floating_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Floating View" android:background="#FF0000" android:textColor="#FFFFFF" android:padding="16dp" android:visibility="gone" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/floating_view" /> </RelativeLayout> ``` 2. 在Activity或Fragment中,设置RecyclerView的布局管理器和适配器: ```java // 找到RecyclerView RecyclerView recyclerView = findViewById(R.id.recyclerview); // 设置布局管理器 recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 设置适配器 recyclerView.setAdapter(adapter); ``` 3. 创建一个自定义的ItemDecoration类(例如:FloatingHeaderDecoration.java): ```java public class FloatingHeaderDecoration extends RecyclerView.ItemDecoration { private View mFloatingView; public FloatingHeaderDecoration(View floatingView) { mFloatingView = floatingView; } @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (parent.getChildAdapterPosition(view) == 0) { outRect.top = mFloatingView.getHeight(); } } @Override public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.onDraw(canvas, parent, state); int top = parent.getPaddingTop(); int bottom = top + mFloatingView.getHeight(); int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); mFloatingView.setVisibility(View.VISIBLE); mFloatingView.layout(left, top, right, bottom); mFloatingView.draw(canvas); } } ``` 4. 在Activity或Fragment中,为RecyclerView添加ItemDecoration: ```java // 找到悬浮视图 View floatingView = findViewById(R.id.floating_view); // 创建自定义的ItemDecoration并添加到RecyclerView recyclerView.addItemDecoration(new FloatingHeaderDecoration(floatingView)); ``` 这样就实现了RecyclerView的悬浮吸顶效果。悬浮视图会在滚动时始终保持在顶部,并且不会被其他项覆盖。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值