Android.GridView实现宫式布局

         应一位朋友的要求,我在博客记录一下自己学习和使用Android开发的一些经验。

         距离Android发布已经三年有余了,可是国内对于Android的开发才刚刚起步(直到Google G1发布才开始关注Android),相关的书籍和资料也确实少得可怜。我不知道自己是过于幸运还是过于可悲,我进公司之后用到的技术都是市场上,或者说在国内,都是比较新的。比如说Extjs,Android,Webwork等。因为新,所以使用和学习的人不多,最重要的是相关资料更是少得可怜。很多时候,只能无奈地跑去外国论坛,寻找资料、线索,学习过程何等痛苦不言而喻。

        言归正传,今天要记录的经验是GridView宫式布局的实现。

        首先提一下,如果看过Android自带的examples的朋友,应该知道例子里面有一个关于GridView的使用范例。没看过的朋友也无所谓,因为今天我们会介绍到。

        范例中介绍了如何使用GridView来实现宫式布局,但是范例写得比较简单,只介绍了如何布局,但是对于应用程序所需的功能来说,介绍得不全面。下面看看范例的运行效果。

 

Android.GridView实现宫式布局

  

       从上面的官方范例可以看出,基本的布局已经实现了。但是这并不是我们所需要的,因为要做宫式布局的话,就必须要在每一个宫,也就是一个格中,放入一个图片,并在图片下面显示文字。可能这个时候,会有人说了,那就把文字写到图片里面啊。是的,这是一种解决办法。但是是最愚蠢和最不可取的方法。因为这样将会导致系统无法实现国际化,而且文字要是有修改的话,就得修改图片,所以这是不可取的。

       有基础的朋友,应该会说,那在格子中加入一个ImageView和TextView啊。对,想法是对的。可是例子中的代码是这样的:

 public class AppsAdapter extends BaseAdapter {

publicAppsAdapter(){

        }

        public View getView(int position, View convertView, ViewGroup parent) {            ImageView i;

            if (convertView == null) {

i=newImageView(Grid1.this);

i.setScaleType(ImageView.ScaleType.FIT_CENTER);

i.setLayoutParams(newGridView.LayoutParams(50,50));

}else{

i=(ImageView)convertView;

            }

            ResolveInfo info = mApps.get(position);            i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

            return i;        }

publicfinalintgetCount(){

returnmApps.size();

        }

        public final Object getItem(int position) {

returnmApps.get(position);

        }

        public final long getItemId(int position) {

returnposition;

}

    }

 mGrid = (GridView) findViewById(R.id.myGrid);        mGrid.setAdapter(new AppsAdapter());

          上面是主要代码,就是自定义一个Adapter来填充GridView。从getView()方法中可以看出,这个适配器只能填充一个View。我尝试加入一个LinearLayout来封装ImageView和TextView,然后在getView()方法返回。但是报错。没有执行成功!

          无奈之下,网上找了一下资料。发现可以使用SimpleAdapter来实现。废话少说,上代码:

 public class MainActivity extends Activity implements OnItemClickListener {

 private String texts[] = null; private Integer images[] = null;

 

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  // 初始化图片数组和文本数组

images=newInteger[]{R.drawable.shoppingcart,

R.drawable.shoppingcart,R.drawable.shoppingcart,

R.drawable.shoppingcart,R.drawable.shoppingcart,

R.drawable.shoppingcart,R.drawable.shoppingcart};

texts=newString[]{"宫式布局1","宫式布局2","宫式布局3","宫式布局4","宫式布局5","宫式布局6",

"宫式布局7"};

//填充GridView

GridViewgridView=(GridView)findViewById(R.id.homeGrid);

SimpleAdaptersimpleAdapter=newSimpleAdapter(this,fillMap(),

R.layout.griditem,newString[]{"imageView","imageTitle"},

newint[]{R.id.imageView,R.id.imageTitle});

gridView.setAdapter(simpleAdapter);

//监听onItemClick事件

gridView.setOnItemClickListener(this);

 }

 public List<Map<String, Object>> fillMap() {

List<Map<String,Object>>list=newArrayList<Map<String,Object>>();

for(inti=0,j=texts.length;i<j;i++){

Map<String,Object>map=newHashMap<String,Object>();

map.put("imageView",images[i]);

map.put("imageTitle",texts[i]);

list.add(map);

}

returnlist;

 } 

 @Override

publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intidx,longarg3){

//TODOAuto-generatedmethodstub

switch(idx){

case0:

startActivity(newIntent(this,ChoiceCarActivity.class));

this.finish();

break;

default:

break;

}

 }

         不急,我先来解释一下代码。代码关键在于SimpleAdapter这个类。

     

 SimpleAdapter simpleAdapter = new SimpleAdapter(this,

                                                                                            fillMap(),                                                                                            R.layout.griditem,

                                                                                            new String[] { "imageView", "imageTitle" },

                                                                                            new int[] { R.id.imageView, R.id.imageTitle });

         第一个参数是Context,也就是上下文。在这里就是MainActivity这个类本身。

         第二个参数是List<Map<String,Object>>,也就是List里面放着一堆Maps,Map里面放着一对Key和Value,Key是String类型,Value是Object类型。这个有什么用呢?其实这里面的List放的Maps,每一个Map对应的就是一个格子,Map里面的对象就是格子里面要放的东西。GridView会从这个List中循环取出每一个Map,然后将Map中的对象一个一个取出来,填到一个格子中。

        第三个参数是R.layout.griditem,这个是一个模板,也就是说GridView的每一个格子都按照这个模板来布局。后面会给出griditem的xml代码。

        第四个参数是new String[]{"imageView","imageTitle"},这个参数是一个String数组,对应着Map的Key,也就是说,Map的key是什么,这里就是什么。GridView会根据这里给的数组的值来从Map中获取对应的Value。

        第五个参数是new int[] {R.id.imageView,R.id.imageTitle},这个参数是一个int数组,对应着第三个参数的模板的控件ID。

       说到这里,估计大家还是不太理解,这个SimpleAdapter是怎么工作的。我现在就详细得说一下,它的工作机制:首先GridView会先从List中循环获取Map,每一次循环List,都会从String数组(第四个参数)中循环取出String数组的值,然后作为Map的key,从而获取到该Map的对应该Key的Value。同时从int数组(第五个参数)中循环取出id值,从R.layout.griditem模板中根据这些id值获取到这些控件。这样,每一次循环List,都将会产生一些控件,和一些Value,按照顺序将Value的值填充到控件中。比如说,控件是TextView,那么这个Value就会赋值到TextView的text属性中,如果是ImageView,那么Value就会赋值到ImageView的src属性中。这样,每循环一次List,该格子就产生了两个控件,一个是ImageView,另一个是TextView,这两个控件都在模板中提前定义了。

      如果大家还不理解的话,我尝试写一些伪代码来帮助大家理解。

List<Map<String,Object>> list;  //第二个参数

String[]    str;//第四个参数

int []  ids;//第五个参数

int k =0;

 for(int i=0,j=list.size();i<j;i++){

            Map<String,Object>  map = (Map<String,Object>)list.get(i);

            Object  image = map.get(str[k]);//第一个Value

            Object   text = map.get(str[k+1]);//第二个Value

             // 获取控件

           ImageView imageView =  (ImageView )findViewById(ids[k]);

           TextView textView =  (TextView )findViewById(ids[k+1]);

          //将Value赋值到控件中

           imageView.setSrc(image);

          textView.setText(text);

          // 将控件加入到GridView的格子中

}

           上面是伪代码,用来描述GridView解析SimpleAdapter的过程。以上纯粹个人理解,不代表实际是这样操作的。如有错误之处,敬请原谅,并请悉心指教。

            下面附上模板XML和GridView的XML:

             1、GridView的main.xml,此为主界面。

 <?xml version="1.0" encoding="utf-8"?>

<GridViewxmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/homeGrid"android:layout_width="fill_parent"

android:layout_height="fill_parent"android:verticalSpacing="10dp"

android:horizontalSpacing="10dp"android:numColumns="auto_fit"

android:columnwidth="90dp"android:stretchMode="columnWidth"

android:gravity="center">

</GridView>

          2、模板griditem.xml,模板必须和main.xml分开为两个XML文件。相互独立。

 <?xml version="1.0" encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"android:layout_height="fill_parent"

android:orientation="vertical">

<ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"

android:layout_height="wrap_content"android:layout_gravity="center_horizontal">

</ImageView>

<TextViewandroid:id="@+id/imageTitle"android:layout_width="wrap_content"

android:layout_height="wrap_content"android:layout_gravity="center_horizontal">

</TextView>

</LinearLayout>

 Android.GridView实现宫式布局

            宫式布局已经完成。下一篇文章将会介绍如何获取用户点击的是哪一宫,哪一个格子。敬请期待。谢谢!

转载请注明文章出处:暗夜星辰 http://kandy0619.blog.163.com/

相关推荐