1.GridView是什么?
GridView又称为网格视图或者九宫格视图,当手机屏幕上需要显示比较多的内容时(包括文字、图片或者其它元素),可以使用GridView。最常见的GridView使用在于早期Android手机的一二级菜单和相册里的照片墙效果,当然如果将GridView的这种布局方式用于软件的主页面用来显示菜单,也是比较好的选择。
2.代码中具体实现
接下来就使用GridView实现照片墙的效果来简单的介绍一下GridView的用法。
实现后的效果:
下面是一些GridView属性:
- android:numColumns="auto_fit" ,GridView的列数设置为自动
- android:columnWidth="90dp",每列的宽度,也就是Item的宽度
- android:stretchMode="columnWidth",缩放与列宽大小同步
- android:verticalSpacing="10dp",两行之间的边距,如:行一(NO.0~NO.2)与行二(NO.3~NO.5)间距为10dp
- android:horizontalSpacing="10dp",两列之间的边距
//GridView的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.chupeng.gridviewdemo.MainActivity">
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:horizontalSpacing="5dp"
android:verticalSpacing="5dp"
android:numColumns="3"
android:listSelector="@android:color/transparent"
android:stretchMode="columnWidth">
</GridView>
</LinearLayout>
//GridView的item的布局文件
<?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:gravity="center">
<com.example.chupeng.gridviewdemo.SquareImageView
android:id="@+id/squareImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/gray"
android:layout_margin="5dp"
android:scaleType="centerCrop"/>
</LinearLayout>
仔细看GridView的item的布局文件可以注意到,这里并没有采用ImageView而是用的是一个叫SquareImageView的自定义View,顾名思义这里就是为了GridView的每个item都是正方形,这样整个照片墙看起来比较整齐美观。需要实现一个正方形的ImageView非常简单,只需要在它的onMeasure方法中将宽和高设置成一样的就好。
package com.example.chupeng.gridviewdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by ChuPeng on 2017/2/25.
*/
public class SquareImageView extends ImageView
{
public SquareImageView(Context context)
{
super(context);
}
public SquareImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
//将宽和高设置为一样的
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
可以看到,我们在SquareImageView的onMeasure()方法中巧妙的将heightMeasureSpec替换为widthMeasureSpec,这样就可以得到一个正方形的ImageView了,这里涉及到了View的工作流程相关的知识。接这需要实现一个GridView的适配器,这里的实现方式跟ListView非常相似。
package com.example.chupeng.gridviewdemo;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
/**
* Created by ChuPeng on 2017/2/25.
*/
public class ImageAdapter extends BaseAdapter
{
private Context context;
private List<Bitmap> list;
public ImageAdapter(Context context, List<Bitmap> list)
{
this.context = context;
this.list = list;
}
public int getCount()
{
return list.size();
}
public Object getItem(int position)
{
return list.get(position);
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup viewGroup)
{
Bitmap bitmap = list.get(position);
View view;
ViewHolder viewHolder;
if(convertView == null)
{
view = LayoutInflater.from(context).inflate(R.layout.gridview_item, null);
viewHolder = new ViewHolder();
viewHolder.squareImage = (SquareImageView) view.findViewById(R.id.squareImage);
//将ViewHolder存储在view中
view.setTag(viewHolder);
}
else
{
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.squareImage.setImageBitmap(bitmap);
return view;
}
class ViewHolder
{
SquareImageView squareImage;
}
}
紧接着将ImageAdapter设置给GridView,这样一个绚丽大方的图片墙就大功告成了
package com.example.chupeng.gridviewdemo;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.GridView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity
{
private List<Bitmap> list;
private Bitmap bitmap;
private GridView gridView;
private ImageAdapter adapter;
private Handler handler;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
gridView = (GridView) findViewById(R.id.gridView);
handler = new Handler()
{
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 123:
adapter = new ImageAdapter(MainActivity.this, (List<Bitmap>) msg.obj);
gridView.setAdapter(adapter);//将ImageAdapter设置给GridView
break;
}
}
};
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Intent intent = new Intent(MainActivity.this, ShowActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable("data", list.get(position));
intent.putExtras(bundle);
startActivity(intent);
}
});
new Thread(new Runnable()
{
public void run()
{
list = new ArrayList<Bitmap>();//给list中添加图片
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.beer);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.bread);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.breakfast);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.burger);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.cake);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.carrot);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.check);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.chicken);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.closed);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.cocktails);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.coffeecup);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.croissant);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.cutlery1);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.cutlery);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.favorite);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.fish);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.fork);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.fruits);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.icecream);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.invoice);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.juice);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.kettle1);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.kettle);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.lobster);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.menu);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.mushrooms);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.napkins);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.open);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.pan);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.paymentmethod);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.pieceofcake);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.pizza);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.reserved);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.restaurant);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.saltandpepper);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.sausage);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.skewer);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.soup);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.spoon);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.steak);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.sushi);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.sushi1);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.sushi);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.table);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.teacup);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.terrace);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.tray1);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.tray);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.vegetables);
list.add(bitmap);
bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.wine);
list.add(bitmap);
Message message = new Message();
message.what = 123;
message.obj = list;
handler.sendMessage(message);
}
}).start();
}
}
3.总结
在MainActivity中将给list中添加图片的功能放到子线程中去操作,这样主要是为了防止图片数量过多造成ANR(主线程进行耗时操作,造成主线程阻塞),可是当在子线程中完成添加图片的操作以后我们不能直接在子线程中完成ImageAdapter的初始化和给GridView设置adapter,因为在ImageAdapter的初始化的过程中需要给SquareImageView
添加图片,这里的过程就属于改变UI的操作,而Android系统不允许在子线程中对UI进行改变,因为在子线程中改变UI是不安全的,所以我们这里还需要利用Handler机制将list传入到主线程中,才能完成接下来的操作,否则将会抛出异常。
以上Demo的源代码地址:点击打开链接