笔者在安卓也是个小白,站在巨人的肩膀上实现了一个Listview,但因为列过多,需要对某些列可以隐藏,于是研究了一下,发现资料比较少,所以有了这篇文章记录一下。
首先讲一下,我的Listview的实现方式:
使用adapter管理数据源和数据的刷新。
public ListTestAutoUpAdapter(Context ctx, List<TestAutoUpDetail> list, RelativeLayout head,boolean[] colsState) {
this.mContext = ctx;
this.autoUpDetailList = list;
this.mHead = head;
this.mInflater = LayoutInflater.from(mContext);
widthArray = new int[]{60,120,60,60,60,60
,60,80,80,80,80,300};
if(colsState == null || colsState.length != 12){
colHideState = new boolean[]{true,true,true,true,true,true,true,true,true,true,true,true};
}else{
colHideState = colsState;
}
Log.d("------", "ListTestAutoUpAdapter: 重新创建");
// hideHeader();
}
public View getView(int i, View convertView, ViewGroup viewGroup) {
ViewHolder holder;
// Log.d("------", "getView: "+i);
if(convertView == null){
//从布局文件item_grid生成转换视图对象
convertView = mInflater.inflate(R.layout.item_test_autoup, viewGroup, false);
holder = new ViewHolder();
CustomHScrollView scrollView = convertView.findViewById(R.id.h_scrollView);
holder.scrollView = scrollView;
//获取布局文件的控件
holder.tv_id = convertView.findViewById(R.id.tv_id);
holder.tv_record_id = convertView.findViewById(R.id.tv_record_id);
holder.tv_created_time = convertView.findViewById(R.id.tv_created_time);
holder.tv_test_context = convertView.findViewById(R.id.tv_test_context);
holder.llItemList = convertView.findViewById(R.id.ll_item_list);
saveLayoutToHolder(holder,convertView);
//将视图持有者保存到转换视图中
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
//设置控件的数据
TestAutoUpDetail testAutoUpDetail = autoUpDetailList.get(i);
holder.tv_id.setText(testAutoUpDetail.id+"");
holder.tv_record_id.setText(testAutoUpDetail.test_record_id+"");
holder.tv_created_time.setText(testAutoUpDetail.getCreatedTimeStr());
holder.tv_test_context.setText(testAutoUpDetail.test_context);
//传入的mHead头布局里获取滚动区域,支持该区域的滚动
CustomHScrollView headSrcrollView = mHead.findViewById(R.id.h_scrollView);
//获取标题里面的父布局,然后同时设置父布局和子布局的显示隐藏状态
hideCols(getHeaderLayoutItems(headSrcrollView),holder);
headSrcrollView.AddOnScrollChangedListener(new OnScrollChangedListenerImp(holder.scrollView));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
headSrcrollView.smoothScrollTo(i, i1);
}
});
}
holder.tv_id.setOnClickListener(new MyOnClickListener(i));
holder.llItemList.setOnClickListener(new MyOnClickListener(i));
return convertView;
}
private void saveLayoutToHolder(ViewHolder holder,View convertView) {
holder.llItems = new LinearLayout[12];
int a = 0;
holder.llItems[a++] = convertView.findViewById(R.id.ll_item1);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item2);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item3);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item4);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item5);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item6);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item7);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item8);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item9);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item10);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item11);
holder.llItems[a++] = convertView.findViewById(R.id.ll_item12);
}
private LinearLayout[] getHeaderLayoutItems(CustomHScrollView headSrcrollView) {
LinearLayout[] llItems = new LinearLayout[12];
int a = 0;
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item1);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item2);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item3);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item4);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item5);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item6);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item7);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item8);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item9);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item10);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item11);
llItems[a++] = headSrcrollView.findViewById(R.id.ll_item12);
return llItems;
}
public void hideCols(LinearLayout[] headerLayouts,ViewHolder holder){
int len = colHideState.length;
int headerLen = headerLayouts.length;
if(holder == null || holder.llItems == null){
return;
}
int lenContent = holder.llItems.length;
if(len != 12 || headerLen != 12 || lenContent != 12){
return;
}
for(int i=0;i<len;i++ ){
if(colHideState[i]){
headerLayouts[i].setVisibility(View.VISIBLE);
holder.llItems[i].setVisibility(View.VISIBLE);
//只设置父布局不可见,返回还是会留下一片空白。需要恢复期宽高
headerLayouts[i].setLayoutParams(new LinearLayout.LayoutParams(widthArray[i],35));
}else{
headerLayouts[i].setVisibility(View.GONE);
holder.llItems[i].setVisibility(View.GONE);
//只设置父布局不可见,返回还是会留下一片空白。通过人为设置其宽高为0强制父布局刷新界面可真正隐藏
headerLayouts[i].setLayoutParams(new LinearLayout.LayoutParams(0,0));
}
}
}
布局是自定义的item_test_autoup.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="horizontal"
android:padding="5dp" >
<!--android:descendantFocusability="blocksDescendants" 避免无法获取焦点-->
<TextView android:id="@+id/tv_id"
android:layout_marginTop="1dp"
android:layout_width="50dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_weight="1"
android:layout_height="@dimen/item_height"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/font_default_dp_size"
android:textColor="@color/black"
android:ellipsize="end"
android:text="序号" />
<com.hope.iotloramonitor.CustomHScrolView.InterceptScrollLinearLayout
android:id="@+id/scroollContainter"
android:layout_width="fill_parent"
android:layout_height="@dimen/item_height"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/tv_id"
android:focusable="false" >
<com.hope.iotloramonitor.CustomHScrolView.CustomHScrollView
android:id="@+id/h_scrollView"
android:layout_width="fill_parent"
android:layout_height="@dimen/item_height"
android:focusable="false"
android:scrollbars="none" >
<LinearLayout
android:id="@+id/ll_item_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/ll_item1"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView android:id="@+id/tv_record_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:text="记录id"
android:gravity="center"
android:textSize="@dimen/font_default_dp_size"
android:textColor="@color/black"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_item2"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView android:id="@+id/tv_created_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:gravity="center"
android:textSize="@dimen/font_default_dp_size"
android:textColor="@color/black"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="创建时间" />
</LinearLayout>
//...省略的代码
<LinearLayout
android:id="@+id/ll_item12"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView android:id="@+id/tv_test_context"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:textSize="@dimen/font_default_dp_size"
android:textColor="@color/black"
android:text="测试内容"/>
</LinearLayout>
</LinearLayout>
</com.hope.iotloramonitor.CustomHScrolView.CustomHScrollView>
</com.hope.iotloramonitor.CustomHScrolView.InterceptScrollLinearLayout>
</RelativeLayout>
然后我的Listview携带标题的后在主界面的格式是这样的:
<?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"
android:id="@+id/content_test_table"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<include layout="@layout/layout_page_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<include
android:id="@+id/head_layout"
layout="@layout/item_test_autoup"
/>
<com.hope.iotloramonitor.InScrollView.InScrollView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:minHeight="100dp"
android:layout_weight="10"
android:cacheColorHint="@android:color/transparent"
android:dividerHeight="1dp"
android:divider="@color/black">
</com.hope.iotloramonitor.InScrollView.InScrollView>
</LinearLayout>
就是下面这样:大家可以忽略其他不相干的布局。主要是看我的listview标题也是用的item_test_autoup.xml
接下来就直奔主题了,根据我查阅的资料,我自己的实现方式是:
1、item_test_autoup.xml里面,listview的每个子控件Textview需要增加一个父布局Linelayout,在adapter的getview里获取每个item的父LineLayout,将其存到viewholder里,然后将这些列的显示隐藏数组传递过来,然后将对应的列显示隐藏。
2、通过传递进来的mHeader标题布局(其实子控件还是item_test_autoup.xml,只是布局的对象不同),获取每个标题对应的父布局Linelaout,然后通过设置父控件View.GONE,可隐藏标题。
以上实现后,已经隐藏了标题和列表了,但是,标题每次变更后经常会保留一片空白,感觉就是一个安卓的bug,因为我明明设置了wrapcontent和view.gone的,但是安卓在重新绘制的时候就是不重新计算标题的宽高,导致我滚动标题的时候,发现列表和标题对不齐。解决办法就是在设置标题的View.GONE后,同时设置其宽高为0,强制其重新计算宽高。当然可见的时候需要还原其原本的宽高,所以在构建adapter里需要初始化一个所有列的宽高进来。