一、产品需求,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>