ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
12.3.1 照片墙效果 实现照片墙效果需要用到GridView,下面先准备好GridView所需的布局文件以及item的布局文件,如下所示。 // GridView的布局文件 <LinearLayout 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" android:orientation="vertical" android:padding="5dp" > <GridView android:id="@+id/gridView1" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:horizontalSpacing="5dp" android:verticalSpacing="5dp" android:listSelector="@android:color/transparent" android:numColumns="3" 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" android:orientation="vertical" > <com.ryg.chapter_12.ui.SquareImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/image_default" /> </LinearLayout> 也许读者已经注意到,GridView的item的布局文件中并没有采用ImageView,而是采用了一个叫SquareImageView的自定义控件。顾名思义,它的作用就是打造一个正方形的ImageView,这样整个照片墙看起来会比较整齐美观。要实现一个宽、高相等的ImageView是非常简单的一件事,只需要在它的onMeasure方法中稍微做一下处理,如下所示。 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 defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } } 可以看出,我们在SquareImageView的onMeasure方法中很巧妙地将heightMeasureSpec替换为widthMeasureSpec,这样什么都不用做就可以一个宽、高相等的ImageView了。关于View的测量等过程的介绍,请读者参看第4章的有关内容,这里不再赘述了。 接着需要实现一个BaseAdapter给GridView使用,下面的代码展示了ImageAdapter的实现细节,其中mUrList中存储的是图片的url: private class ImageAdapter extends BaseAdapter { ... @Override public int getCount() { return mUrList.size(); } @Override public String getItem(int position) { return mUrList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent){ ViewHolder holder = null; if (convertView == null) { convertView = mInflater.inflate(R.layout.image_list_item, parent, false); holder = new ViewHolder(); holder.imageView = (ImageView) convertView.findViewById(R. id.image); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } ImageView imageView = holder.imageView; final String tag = (String)imageView.getTag(); final String uri = getItem(position); if (! uri.equals(tag)) { imageView.setImageDrawable(mDefaultBitmapDrawable); } if (mIsGridViewIdle && mCanGetBitmapFromNetWork) { imageView.setTag(uri); mImageLoader.bindBitmap(uri, imageView, mImageWidth, mImage- Width); } return convertView; } } 从上述代码来看,ImageAdapter的实现过程非常简捷,这几乎是最简洁的BaseAdapter的实现了。但是简洁并不等于简单,getView方法中核心代码只有一句话,那就是:mImageLoader.bindBitmap(uri, imageView, mImageWidth, mImageWidth)。通过bindBitmap方法很轻松地将复杂的图片加载过程交给了ImageLoader, ImageLoader加载图片以后会把图片自动设置给imageView,而整个过程,包括内存缓存、磁盘缓存以及图片压缩等工作过程对ImageAdapter来说都是透明的。在这种设计思想下,ImageAdapter什么也不需要知道,因此这是一个极其轻量级的ImageAdapter。 接着将ImageAdapter设置给GridView,如下所示。到此为止一个绚丽的图片墙就大功告成了,是不是惊叹于如此简捷而又优美的实现过程呢? mImageGridView = (GridView) findViewById(R.id.gridView1); mImageAdapter = new ImageAdapter(this); mImageGridView.setAdapter(mImageAdapter); 最后,看一下我们亲手打造的图片墙的效果图,如图12-1所示。是不是看起来很优美呢? :-: ![](https://img.kancloud.cn/39/b8/39b8fc07f162102fc5c10e955ccdcbd6_348x604.png) 图12-1 采用ImageLoader实现的照片墙 另外,本节中的照片墙应用首次运行时会从网络中加载大量图片,这会消耗若干MB的流量,因此建议首次运行时选择WiFi环境,同时程序启动时也会有相应的提示,在非WiFi环境下,打开应用时会弹出如下提示,请读者运行时注意一下,避免消耗过多的流量。 if (! mIsWifi) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("初次使用会从网络中下载大概5MB的图片,确认要下载吗?"); builder.setTitle("注意"); builder.setPositiveButton("是", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mCanGetBitmapFromNetWork = true; mImageAdapter.notifyDataSetChanged(); } }); builder.setNegativeButton("否", null); builder.show(); }