转载自:http://blog.csdn.net/qibin0506/article/details/41776165
无意间看到京东的分类列表做的非常炫, 是那种横排列表的形式,本来是想截图上来的,但是公司没找到数据线。。。。好吧,今天我们也来实现个这种效果。 这次我选择的ListView,但是ListView默认是横向铺满屏的,怎么做到并排呢? 重写!!!
虽然京东的没法截图了,但是我自己做的效果可以在模拟器上运行,先来看看效果吧,界面有点丑,没关系,对吧? 我们主要研究的是如何实现这种框架,而不是界面本身。
恩, 界面确实有点丑,算了,还是直接看实现过程吧。
上面说了,这次我们选重写ListView, 那么我们的需求是什么呢? 很简单,重写它默认横向铺满屏的特性,让它可以wrap_content。
- public class MyListView extends ListView {
- public MyListView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int height = getMeasuredHeight();
- int width = 0;
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- if(widthMode == MeasureSpec.EXACTLY) {
- width = widthSize;
- }else {
- if(widthMode == MeasureSpec.AT_MOST) {
- final int childCount = getChildCount();
- for(int i=0;i<childCount;i++) {
- View view = getChildAt(i);
- measureChild(view, widthMeasureSpec, heightMeasureSpec);
- width = Math.max(width, view.getMeasuredWidth());
- }
- }
- }
- setMeasuredDimension(width, height);
- }
- }
还是很简单的, 只重写了onMeasure()方法, 看看具体的逻辑吧。
13行,首先调用了super.onMeasure()方法,因为这里我们不考虑height,所以让ListView自己去算吧,我们只关心width/
14行,获取了ListView自己测量的结果,我们只需要height,因为width是我们自己需要计算的。
17~18行,不说了,获取父布局给推荐的mode和size。
接下来是一个if...else..., 在我们这个需求里,这个if...else...是多余的,但为了代码规范,还是加上了,有总比没有强吧。
if里,if的条件是widthMode == MeasureSpec.EXACTLY 即为精确值时, 这时候就不需要我们自己去计算了,直接赋值width为父布局给推荐的大小就ok。
看else里,这里又一个if,这个条件widthMode == MeasureSpec.AT_MOST 即当mode为尽量大时,也就是layout_width="wrap_content",好,这里需要我们自己做工作了。
23行,我们获取了所有的子item的个数。
接着24行一个for循环,获取所有的子view。
26行,通过measureChild(view, widthMeasureSpec, heightMeasureSpec);去测量一下该view的宽高。
27行,用width保存所有子view中宽度最大的那个的宽度。
最后的最后,32行,别忘了保存一下测量结果。
ok,重写的ListView搞定了,现在它就有了wrap_content的能力,赶紧来布局中布局它吧。
- <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"
- tools:context=".MainActivity" >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:weightSum="3" >
- <org.loader.jdmemu.MyListView
- android:id="@+id/list1"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:background="@android:color/darker_gray" />
- <org.loader.jdmemu.MyListView
- android:id="@+id/list2"
- android:layout_width="0dip"
- android:layout_weight="2"
- android:layout_height="wrap_content" />
- </LinearLayout>
- </RelativeLayout>
可以看到,这里是两个并排的ListView,占的宽度比为1:2。前期工作都做完了,去Activity中填充数据看看效果吧。
- public class MainActivity extends Activity {
- private static final String[] mMenus = { "常用分类", "服饰内衣", "鞋靴", "手机",
- "家用电器", "数码", "电脑办公", "个护化妆", "图书" };
- private MyListView mListView1;
- private MyListView mListView2;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mListView1 = (MyListView) findViewById(R.id.list1);
- mListView2 = (MyListView) findViewById(R.id.list2);
- mListView1.setAdapter(new ArrayAdapter<String>(this,
- R.layout.menu, mMenus));
- mListView1.setOnItemClickListener(new ItemClick());
- }
- private class ItemClick implements OnItemClickListener {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position,
- long id) {
- mListView1.smoothScrollToPositionFromTop(position, 0);
- String[] items = new String[(position + 1) * 2];
- for(int i=0;i<items.length;i++) {
- items[i] = mMenus[position] + "中的数据:" + i;
- }
- mListView2.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, items));
- }
- }
- }
恩,偷懒了,不过很好理解,就是为ListView1设置一个adapter,并通过ListView的itemClick动态改变ListView2的adapter。
重点看看
- mListView1.smoothScrollToPositionFromTop(position, 0);
这句话的作用就是实现当我们点击该item时,让该ListView滑动,并到在该item到达顶部时停止,实现动画中那个自动滑动的ListView的效果。
如此简单,就可以达到文章刚开始的效果。
等等,突然想到,是不是可以把菜单做成侧滑的效果呢? 嘿嘿,应该还没有人这么干吧。 看来下篇文章可能就是“不一样的侧滑菜单了”。嘿嘿,今天下班回去研究研究。