ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 导读 在本篇文章中,你将学到: - 如何实现广告位和列表的整体下拉刷新。 - ListView的两层嵌套。 - 如何让ListView中的一行显示多个Item。 - ### 先睹为快 项目的首页主要分为两部分: 1. 上部的轮播广告位 1. 下部的商品展示区,在每个商品类别(如,美食,服装,办公用品)下,最多展示6个商品。 > 效果图:    ![这里写图片描述](https://box.kancloud.cn/2016-03-17_56ea50d234137.jpg "") 不同的分类:       ![这里写图片描述](https://box.kancloud.cn/2016-03-17_56ea50d28117f.jpg "") ### 布局思路 ![这里写图片描述](https://box.kancloud.cn/2016-03-17_56ea50d2bf0a3.jpg "") 描述:每个ListView都由HeadView、主体和FooterView组成。 整体:PullToRefreshListView 广告位:PullToRefreshListView的HeaderView 商品展示区:PullToRefreshListView的主体 每个商品大类(如美食类):PullToRefreshListView的一个Item 每个大类下的六个商品:ExpandedListView 每个商品:ExpandedListView的Item ### 实现 ### 布局文件 首页布局:active_main.xml ~~~ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_weight="1" tools:context=".MainActivity" > <!-- 顶部搜索框 --> <LinearLayout android:id="@+id/main_top_layout" android:layout_width="match_parent" android:layout_height="45dp" android:layout_alignParentTop="true" android:background="@color/logoColor" android:focusableInTouchMode="true" android:gravity="center_horizontal" android:orientation="horizontal" > <ImageView android:id="@+id/main_top_logo" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:src="@drawable/main_top_logo" /> <EditText android:id="@+id/main_search_edit" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:layout_weight="1" android:background="@drawable/bg_searchbox" android:focusable="false" android:focusableInTouchMode="true" android:hint="查询商品" android:padding="6dp" android:textColor="@color/darkgray" android:textSize="12sp" android:windowSoftInputMode="stateVisible|adjustPan" /> <ImageView android:id="@+id/index_search_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:paddingLeft="10dp" android:paddingRight="10dp" /> </LinearLayout> <!-- 广告位和商品分类列表(整体都在一个下拉刷新的ListView当中) --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginTop="45dp"> <jczb.shoping.widget.PullToRefreshListView android:id="@+id/product_floor_listview" style="@style/widget_listview" android:scrollbars="none" /> </LinearLayout> </RelativeLayout> ~~~ HeaderView布局:main_advertisement_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:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <LinearLayout android:layout_width="match_parent" android:layout_height="136dp" android:background="#00FFFFFF"> <!-- 广告位中可以左右滑动的控件 --> <android.support.v4.view.ViewPager android:id="@+id/adv_pager" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v4.view.ViewPager> </LinearLayout> <!-- 广告位中的小圆点 --> <LinearLayout android:id="@+id/viewGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="115dp" android:layout_marginRight="10dp" android:gravity="right" android:orientation="horizontal" > </LinearLayout> </RelativeLayout> </LinearLayout> ~~~ 商品大类Item布局:main_lv_item.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="match_parent" android:orientation="vertical" android:background="#FFFFFF"> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:orientation="horizontal" > <!-- 商品分类名称 --> <TextView android:id="@+id/tv_category_name" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="美食" android:layout_alignParentLeft="true" android:layout_marginLeft="10dp" android:layout_marginTop="7dp" android:textSize="20dp" /> <ImageView android:id="@+id/iv_category_color" android:layout_width="7dp" android:layout_height="match_parent" android:background="#55D155"/> <!--更多箭头 --> <ImageView android:id="@+id/iv_product_more" android:layout_width="15dp" android:layout_height="15dp" android:layout_alignParentRight="true" android:layout_marginTop="14dp" android:layout_marginRight="5dp" android:layout_marginLeft="3dp" android:src="@drawable/tb_icon_actionbar_back1" /> <!--更多文本 --> <TextView android:id="@+id/tv_product_more" android:layout_height="wrap_content" android:layout_width="wrap_content" android:paddingRight="8dp" android:layout_toLeftOf="@id/iv_product_more" android:layout_marginTop="10dp" android:text="更多" android:textSize="16dp" /> </RelativeLayout> <!-- 分割线 --> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="#C0C0C0" /> <!--商品大类 --> <jczb.shoping.adapter.ExpandedListView android:id="@+id/elv_main_category" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="#FFFFFFFF" android:listSelector="#00000000" > </jczb.shoping.adapter.ExpandedListView> <!-- 分割线 --> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="#C0C0C0" /> <!-- 分割线 --> <View android:layout_width="match_parent" android:layout_height="8dp" android:background="#F6F9FE" /> </LinearLayout> ~~~ 每个商品的Item布局:main_lv_item_item.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="match_parent" android:orientation="horizontal" > <!--每行展示 2个商品--> <LinearLayout android:layout_width="fill_parent" android:layout_height="250dp" android:layout_marginLeft="0dp" android:layout_marginRight="0dp" android:layout_marginTop="0dp" android:layout_marginBottom="0dp" android:orientation="horizontal" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" > <ImageView android:id="@+id/iv_main_product_1" android:layout_width="match_parent" android:layout_height="170dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginBottom="10dp" android:background="#FFFFFF" android:scaleType="fitXY" /> <TextView android:id="@+id/tv_main_productName_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/iv_main_product_1" android:layout_alignLeft="@id/iv_main_product_1" android:layout_marginBottom="5dp" android:layout_marginLeft="5dp" android:textSize="13dp" android:lines="2" android:ellipsize="end" /> <TextView android:id="@+id/tv_main_productPrice_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_main_productName_1" android:layout_marginLeft="5dp" android:textColor="#E2572D" android:textSize="14dp"/> </RelativeLayout> <RelativeLayout android:layout_width="2dp" android:layout_height="fill_parent" android:background="#FFFFFF" > </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" > <ImageView android:id="@+id/iv_main_product_2" android:layout_width="match_parent" android:layout_height="170dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginBottom="10dp" android:background="#FFFFFF" android:scaleType="fitXY" /> <TextView android:id="@+id/tv_main_productName_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/iv_main_product_2" android:layout_marginLeft="5dp" android:textSize="13dp" android:lines="2" android:ellipsize="end" android:layout_marginBottom="5dp" /> <TextView android:id="@+id/tv_main_productPrice_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_main_productName_2" android:layout_marginLeft="5dp" android:textColor="#E2572D" android:textSize="14dp"/> </RelativeLayout> </LinearLayout> </LinearLayout> ~~~ ### ListView - PullToRefreshListView(此处省略) - ExpandedListView ~~~ package jczb.shoping.adapter; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.widget.ListView; /** * 用于ListView的嵌套,这个ListView当中可以嵌套ListView * @author xuchenyang * 2015年11月9日21:43:01 */ public class ExpandedListView extends ListView{ public ExpandedListView(Context context) { super(context); setBackgroundColor(Color.argb(100, 0, 55, 55)); } public ExpandedListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public ExpandedListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } } ~~~ ### Adapter - PullToRefreshListView的Adapter ~~~ product_floor_listview.setAdapter(new BaseAdapter() { @Override public View getView(int position, View convertView, ViewGroup parent) { View inflate = getLayoutInflater().inflate(R.layout.main_lv_item, null); /*设置商品分类名称*/ //获得显示商品分类的控件 TextView tvCategoryName=(TextView)inflate.findViewById(R.id.tv_category_name); //从数据集合中获得分类名称 String strCategoryName=lstHomePage.get(position).getName(); //设置控件文本 tvCategoryName.setText(strCategoryName); /*设置商品分类名称的颜色*/ ImageView ivCategoryColor=(ImageView)inflate.findViewById(R.id.iv_category_color); //黄,绿,红,蓝 String[] colorValues={"#FFFF77","#55D155","#DB3031","#6278D9"}; int colorIndex=position % 4; int colorValue=Color.parseColor(colorValues[colorIndex]); ivCategoryColor.setBackgroundColor(colorValue); /*设置每个分类下的商品*/ List<Product> lstProduct=lstHomePage.get(position).getProduct(); ListView listView = (ListView) inflate.findViewById(R.id.elv_main_category); productAdapter=new MainListViewAdapter(MainActivity.this,lstProduct); listView.setAdapter(productAdapter); return inflate; } @Override public long getItemId(int position) { return position; } @Override public Object getItem(int position) { return lstHomePage.get(position); } /** * 显示的商品类别数 */ @Override public int getCount() { return lstHomePage.size(); } }); /*添加下拉刷新事件*/ product_floor_listview.setOnRefreshListener(new OnRefreshListener(){ @Override public void onRefresh() { // Do work to refresh the list here. new GetDataTask().execute(); } }); } ~~~ - MyListViewAdapter ~~~ package jczb.shoping.adapter; import java.util.List; import jczb.shoping.common.UIHelper; import jczb.shoping.model.Product; import jczb.shoping.model.URLs; import jczb.shoping.ui.ProductsInfoActivity; import jczb.shoping.ui.R; import net.tsz.afinal.FinalBitmap; import android.content.Context; import android.content.Intent; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; /** * 首页每个分类下商品展示的ListView的Adapter * @author xuchenyang * 2015年11月9日20:11:10 */ public class MainListViewAdapter extends BaseAdapter { //某个商品分类下商品集合 private List<Product> list; private Context context; private FinalBitmap fb; public MainListViewAdapter(Context context, List<Product> list) { this.context = context; fb = FinalBitmap.create(context); this.list = list; } /** * 获得记录的行数 */ @Override public int getCount() { // 按每行2个显示,算出共显示的行数 if (list.size() % 2 == 0) { return list.size() / 2; } return list.size() / 2 + 1; } /** * 获得每个条目项 */ @Override public Object getItem(int position) { return list.get(position); } /** * 获得每个条目的Id */ @Override public long getItemId(int position) { return position; } /** * 获得每个条目的视图 */ @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = View.inflate(context, R.layout.main_lv_item_item, null); //商品的图片 viewHolder.iv_product1 = (ImageView) convertView .findViewById(R.id.iv_main_product_1); viewHolder.iv_product2 = (ImageView) convertView .findViewById(R.id.iv_main_product_2); //商品名称 viewHolder.tv_name1=(TextView)convertView.findViewById(R.id.tv_main_productName_1); viewHolder.tv_name2=(TextView)convertView.findViewById(R.id.tv_main_productName_2); //商品价格 viewHolder.tv_price1=(TextView)convertView.findViewById(R.id.tv_main_productPrice_1); viewHolder.tv_price2=(TextView)convertView.findViewById(R.id.tv_main_productPrice_2); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } int position1 = position *2; int position2 = position * 2 + 1; Product product1=list.get(position1); /********每行第一个产品的设置********/ //显示产品图片 String pic1 = URLs.imageUrlPrefix+product1.getPro_img(); fb.display(viewHolder.iv_product1, pic1); //假数据 //viewHolder.iv_product1.setImageResource(R.drawable.clothing_04); //显示产品名称 viewHolder.tv_name1.setText(product1.getPro_name()); //显示产品价格 viewHolder.tv_price1.setText("¥"+product1.getPro_price()); //把该产品的位置设为图片的tag值,为的是点击图片时能获得它的位置 //viewHolder.iv_product1.setTag(position1); //把商品的Id保存到Tag中 viewHolder.iv_product1.setTag(product1.getUid()); /***********每行第二个产品的设置*******/ if (position2 < list.size()) { Product product2=list.get(position2); String pic2 =URLs.imageUrlPrefix+product2.getPro_img(); fb.display(viewHolder.iv_product2, pic2); //viewHolder.iv_product2.setImageResource(R.drawable.clothing_0108); //显示产品名称 viewHolder.tv_name2.setText(product2.getPro_name()); //显示产品价格 viewHolder.tv_price2.setText("¥"+product2.getPro_price()); //viewHolder.iv_product2.setTag(position2); viewHolder.iv_product2.setTag(product2.getUid()); } else { //viewHolder.iv_product2.setVisibility(View.GONE); } viewHolder.iv_product1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { UIHelper.ToastMessage(context, v.getTag().toString()); //获得产品uid int uid=Integer.parseInt(v.getTag().toString()); StartProductInfoActivity(uid); } }); viewHolder.iv_product2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(v.getTag()!=null){ UIHelper.ToastMessage(context, v.getTag().toString()); //获得产品uid int uid=Integer.parseInt(v.getTag().toString()); StartProductInfoActivity(uid); } } }); return convertView; } /** * 每个条目项的视图集合 * @author xuchenyang * */ class ViewHolder { private ImageView iv_product1, iv_product2; private TextView tv_name1,tv_name2,tv_price1,tv_price2; } /** * 启动商品详情页 * @param uid 商品id */ public void StartProductInfoActivity(int uid){ Intent intent=new Intent(); intent.putExtra("uid", uid); intent.setClass(context, ProductsInfoActivity.class); context.startActivity(intent); } } ~~~ ### 总结 - 实现广告位和列表的整体下拉刷新: 将广告位作为ListView的HeaderView。 - ListView的两层嵌套: 嵌套进去的ListView要重新实现OnMeasure方法,否则会报错。 - 如何让ListView中的一行显示多个Item: 在Adapter的getCount方法中进行处理。 基本的ListView我想大家都会实现,但是在这个用户体验度要求很高的Android世界里,怎么能不玩出一点花样呢?ListView,原来可以展现出这么好看的界面,太棒了!有没有豁然开朗的感觉?所以尽情想象吧,我已经陶醉了…… ### 附:[下载源码](http://download.csdn.net/detail/u010924834/9270967)