做一个学科知识点的目录功能,这里采用了listview嵌套listview的方式实现,这里记录一些做过程中遇到的值得记录下来的点,先看效果图:
主界面:
展开子知识点界面:
(1)listview加header,activity_subject_home_header.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:baselineAligned="false" android:orientation="horizontal" android:background="@color/subject_background" > <RelativeLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginTop="20dp" android:layout_marginBottom="10dp" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" > <TextView android:id="@+id/forecast_score_text_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="预测分" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/forecast_score_text_tv" android:layout_centerHorizontal="true" android:orientation="horizontal" > <TextView android:id="@+id/forecast_score_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="36" android:textSize="40sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分" /> </LinearLayout> </RelativeLayout> </RelativeLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginTop="20dp" android:layout_marginBottom="10dp" android:gravity="center_horizontal" > <View android:layout_width="2dp" android:layout_height="60dp" android:background="@color/subject_finish_text" /> </LinearLayout> <RelativeLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginTop="20dp" android:layout_marginBottom="10dp" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" > <TextView android:id="@+id/beat_text_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="打败考生" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/beat_text_tv" android:layout_centerHorizontal="true" android:orientation="horizontal" > <TextView android:id="@+id/beat_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="25" android:textSize="40sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="%" /> </LinearLayout> </RelativeLayout> </RelativeLayout> </LinearLayout>
往listview加入:
/** * 接着上面说的添加header,添加header时调用的addHeaderView方法必须放在listview.setadapter前面,意思很明确就是如果想给listview添加头部则必须在给其绑定adapter前添加,否则会报错。原因是当我们在调用setAdapter方法时会android会判断当前listview是否已经添加header,如果已经添加则会生成一个新的tempadapter,这个新的tempadapter包含我们设置的adapter所有内容以及listview的header和footer。所以当我们在给listview添加了header后在程序中调用listview.getadapter时返回的是tempadapter而不是我们通过setadapter传进去的adapter。如果没有设置adapter则tempadapter与我们自己的adapter是一样的。listview.getadapter().getcount()方法返回值会比我们预期的要大,原因是添加了header。 */ LinearLayout hearderViewLayout = (LinearLayout)LayoutInflater.from(this).inflate(R.layout.activity_subject_home_header, null); rootPointListView.addHeaderView(hearderViewLayout, null, false);
2 点击外层listview(根知识点),展开子知识点的listview,原本子知识点的listview就存在布局中,只是平时是躲藏状态,点击后就将它的可视状态设置为visible,这里还得做一个事就是计算出子知识点的listview的高度:
if(isExpend[position] == true){ setListViewHeightBasedOnChildren(holder.pointsListView); holder.pointsListView.setVisibility(View.VISIBLE); holder.showKnowledgePointsImageView.setImageResource(R.drawable.slid_up); }else{ holder.pointsListView.setVisibility(View.GONE); holder.showKnowledgePointsImageView.setImageResource(R.drawable.slid_down); }
/** * 动态计算listview的高度 * @param listView */ public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)) + 20; listView.setLayoutParams(params); }
不重新计算子知识点的listview高度的话,那子listview是显示不出来的。
3 点击外层listview(根知识点)的一个item,将该item上移,不考虑其它情况的话,可以简单实现如下,
在点击item事件里加入如下代码:
int topPosition = ((LinearLayout)clickView.getParent()).getTop();//向顶端滑动 rootPointListView.smoothScrollBy(topPosition,200);
这里考虑的情况还包括了,点击了其中一个item,原来展开的item子listview也得关闭掉,这里就使用了getViewTreeObserver(注册监听视图树的观察者(observer),在视图树种全局事件改变时得到通知。这个全局事件不仅还包括整个树的布局,从绘画过程开始,触摸模式的改变等),等listview绘制完后,再将根知识点的item上移:
/** * 设置观察者,当listview重绘结束后,再重新计算listview的被点击item上移的高度,将该item顶到最顶部 */ rootPointListView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if(clickView != null){ int topPosition = ((LinearLayout)clickView.getParent()).getTop();//向顶端滑动 rootPointListView.smoothScrollBy(topPosition,200); } } });
4 闭合一个展开的子知识点listview时,为了不让根知识点的listview产生抖动现象,这里得在点击事件时,将clickView设置为空,不让到走观察者的smoothScrollBy方法:
OnClickListener clickListener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.show_knowledge_points_layout: case R.id.root_subject_layout: int clickPosition = (Integer)v.getTag(); isExpend[clickPosition] = !isExpend[clickPosition]; if(isExpend[clickPosition] == true){//说明要展开 if(lastClickPosition != -1 && pointListViewList[lastClickPosition] != null && pointListViewList[lastClickPosition].getVisibility() == View.VISIBLE){ pointListViewList[lastClickPosition].setVisibility(View.GONE); CLog.d(TAG , "===============>visibale"); } /** * 记录点击的view,这里之所以记录下来,是因为我们上面将上次展开的子知识点合闭,这个变化,会引起计算item移动到顶部高度, * 所以不能在这里就将高度计算出来 topPosition = ((LinearLayout)clickView.getParent()).getTop(); * 而是放在OnGlobalLayoutListener里面 */ clickView = v; } else {//关闭展开的子知识点,这里将topPosition=0,让关闭时位置停留在原地,不会出现关闭抖动现像 clickView = null; } resetIsExpendArray(clickPosition);//重置点击的数组状态,只允许一个item子知识点展开 notifyDataSetChanged(); lastClickPosition = clickPosition; Log.e("RootPointsAdapter", "isExpend:" + (Integer)v.getTag() + " == true"); break; default: break; } } };
5 关闭软键盘,在AndroidManifest.xml里设置一下就行,不然,因为搜索的那个输入框的作为第一个能获取到焦点的控件需要打开软键盘,所以每次进这个页面都会打开软键盘,android:windowSoftInputMode="stateHidden"闭关它:
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.listviewdemo.MainActivity" android:label="@string/app_name" android:windowSoftInputMode="stateHidden" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
6 进度条圆环,看下一篇博文。
代码见附件
相关推荐
总结来说,实现Android的ListView嵌套ListView需要理解ListView的工作机制,创建并管理两个Adapter,以及在布局文件中正确地嵌套ListView。这虽然不是特别高深的技术,但却是Android开发中常见的需求,熟练掌握能...
接下来,我们讨论ListView嵌套ListView的时间轴效果。时间轴通常用于展示按时间顺序排列的事件,如社交媒体的动态更新。在这种情况下,主ListView用于展示各个时间点,而每个时间点下又可能有多个子事件,这些子事件...
在这个"ListView嵌套控件.zip"压缩包中,包含了一个关于如何模拟ListView嵌套效果的示例,主要涉及ComboBox和菜单栏的形式。 首先,我们来讨论ListView与ComboBox的结合使用。ComboBox是一种下拉列表框,它可以提供...
标题"listView嵌套listViewDemo"指的是一个示例项目,旨在解决此类问题。描述中提到,这个Demo解决了子ListView无法完全显示所有内容的困境,这是通过自定义ListView实现的。 ListView嵌套ListView的问题通常出现在...
本项目"ListView嵌套ListView带多选,全选,反选,选中数量"着重解决了在嵌套ListView中实现多选、全选、反选以及动态显示选中数量的功能。下面将详细介绍这些关键知识点。 1. **嵌套ListView**: 在Android中,...
标题“ListView嵌套ListView全选,多选”涉及到的关键知识点主要包括以下几个方面: 1. **嵌套ListView**:在一个ListView的每个Item内部再放置一个ListView,这样可以形成树状结构,便于展示层次化的数据。这种...
嵌套ListView意味着在一个ListView的每个项视图(item view)中包含另一个ListView。这种方式可以让用户在滚动主列表时,同时看到并交互子列表,以展现层次化的数据。 要实现这样的功能,我们需要以下步骤: 1. **...
下面将详细解释如何实现Android中的ListView嵌套。 1. **基础概念** - **ListView**: Android提供的可滚动视图,用于显示一系列相同的数据项。 - **Adapter**: ListView的数据源,负责将数据转化为ListView可显示...
然而,有时我们可能需要在一个ListView的每个项中再嵌套一个ListView,以实现更复杂的数据展示,这种技术通常被称为“ListView嵌套”。本篇文章将深入探讨如何在Android中实现两个ListView的嵌套使用,并基于提供的...
然而,在某些复杂的界面设计中,我们可能需要在一个ListView中嵌套另一个ListView,这就是所谓的"ListView嵌套ListView"。这种布局方式可以帮助我们实现更丰富的用户界面,比如在商品详情页显示多个级别的属性选项。...
当需要在一个列表项中展示多行多列的数据时,就会用到ListView嵌套GridView的技巧。以下是对这一主题的详细解释。 ### ListView ListView是一种滚动视图,能够显示一列或多列数据,通常用于显示大量可滚动的项目。...
当需要在一个列表项中展示多个子项时,就会用到ListView嵌套GridView的布局方式。本示例提供了“listView嵌套GridView的demo”,帮助开发者理解和实现这种复杂的布局结构。 首先,我们来理解ListView。ListView是一...
当需要在一个列表项中嵌入一个小型的网格布局时,就会涉及到“ListView嵌套GridView”的场景。本篇将详细介绍如何实现这个功能,并解决完全显示GridView内容以及滚动不卡顿的问题。 首先,我们来了解ListView的基本...
listView嵌套横向listView,参考http://blog.csdn.net/whitley_gong/article/details/48936689 的代码的,只是希望日后自己方便,希望作者不要介意。谢谢
本教程将通过一个“ListView嵌套Gridview”的Demo来探讨如何在Android应用中实现这种复杂布局。 首先,我们来理解ListView。ListView是一种可滚动的视图,可以显示一列垂直排列的数据项。它的工作原理是利用Adapter...
然而,在某些复杂的界面设计中,我们可能需要在一个ListView中嵌套另一个ListView,这就涉及到"ListView嵌套"的技术。这种技术可以用来构建层级结构的数据展示或者创建复杂的布局。本篇文章将详细探讨如何在Android...
然而,有时我们需要在一个ListView的项中再嵌套另一个ListView来实现更复杂的布局结构,这就是所谓的“ListView嵌套ListView”。这种技术通常用于呈现层级数据,例如目录树、论坛帖子等。在Android Studio环境下,...
本文将详细介绍如何在Android中实现ListView嵌套GridView的解决方案。 首先,理解基本概念。ListView是一个可滚动的视图,用于显示一系列基于单行的数据项,通常用于长列表的显示。GridView则是布局管理器,它将子...
在某些场景下,我们可能需要在一个ListView中嵌套另一个ListView,以实现更复杂的视图结构,这种技术通常称为“ListView嵌套ListView”。下面将详细讨论这个主题。 首先,我们来看“ListView嵌套ListView”的基本...