### 導讀
在本篇文章中,你將學到:
- 如何實現廣告位和列表的整體下拉刷新。
- ListView的兩層嵌套。
- 如何讓ListView中的一行顯示多個Item。
-
### 先睹為快
項目的首頁主要分為兩部分:
1. 上部的輪播廣告位
1. 下部的商品展示區,在每個商品類別(如,美食,服裝,辦公用品)下,最多展示6個商品。
> 效果圖:

不同的分類:

### 布局思路

描述:每個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)