搜索
热搜: 活动 交友 discuz
查看: 5122|回复: 0
打印 上一主题 下一主题

Android仿微信朋友圈图片查看器

[复制链接]

160

主题

165

帖子

814

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
814
跳转到指定楼层
楼主
发表于 2016-8-17 21:28:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
博文之前,希望大家先打开自己的微信点到朋友圈中去,仔细观察是不是发现朋友圈里的有个“九宫格”的图片区域,点击图片又会跳到图片的详细查看页面,并且支持图片的滑动和缩放?这个功能是不是很常用呢?!那么我今天正好做了这个Demo,下面为大家讲解一下。首先按照惯例先看一下效果图吧,尤其不会录制gif动画(哎~没办法,模拟器不支持多点触控,刚好我的手机又没有Root,不能录屏,悲催啊,大家见谅,想要看真实效果的话,烦请移到博文最下方,点击下载源码,运行后再看效果哈~~),这里先就拿几张静态的图片顶替一下好了。见谅!



效果嘛,将就着看吧!实在看不明白就想想微信朋友圈,或者拖到下方,点击下载源码!这里,首先分析一下主界面吧,布局都是很简单的,主界面仅仅就是一个ListView的控件,ListView的Item上值得注意的是,Item上包含了一个GridView,这个GridView呗用作实现“九宫格”的效果,主界面布局就是一个ListView,这里不说了,我们先来看看ListView的Item的布局吧,以下是item_list.xml


  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:paddingBottom="5dp"
  6.     android:paddingTop="5dp" >

  7.     <ImageView
  8.         android:id="@+id/iv_avatar"
  9.         android:layout_width="50dp"
  10.         android:layout_height="50dp"
  11.         android:background="@drawable/ic_launcher"
  12.         android:scaleType="centerCrop" />

  13.     <TextView
  14.         android:id="@+id/tv_title"
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:layout_marginLeft="5dp"
  18.         android:layout_toRightOf="@id/iv_avatar"
  19.         android:text="爷,今天心情好!"
  20.         android:textSize="16sp" />

  21.     <TextView
  22.         android:id="@+id/tv_content"
  23.         android:layout_width="wrap_content"
  24.         android:layout_height="wrap_content"
  25.         android:layout_below="@+id/tv_title"
  26.         android:layout_marginLeft="5dp"
  27.         android:layout_marginTop="3dp"
  28.         android:layout_toRightOf="@id/iv_avatar"
  29.         android:text="今天又是雾霾!"
  30.         android:textSize="16sp" />

  31.     <com.example.imagedemo.NoScrollGridView
  32.         android:id="@+id/gridview"
  33.         android:layout_width="220dp"
  34.         android:layout_height="wrap_content"
  35.         android:layout_below="@id/tv_content"
  36.         android:layout_marginLeft="5dp"
  37.         android:layout_marginTop="3dp"
  38.         android:layout_toRightOf="@id/iv_avatar"
  39.         android:columnWidth="70dp"
  40.         android:gravity="center"
  41.         android:horizontalSpacing="2.5dp"
  42.         android:numColumns="3"
  43.         android:stretchMode="columnWidth"
  44.         android:verticalSpacing="2.5dp" />

  45. </RelativeLayout>
复制代码


好了,大家看到了,布局也是极其简单的,但是有个问题就是ListView嵌套进了GridView,那么就会出现一个问题,导致GridView显示的不全,那么该怎么解决这个问题呢?其实也简单,就是重写一个GridView,测量一下GridView的高度,再设置上去。具体解决方案请看上篇博文ListView嵌套GridView显示不全解决方法或者源码,如下NoScrollGridView.java
  1. package com.example.imagedemo;

  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.widget.GridView;

  5. /**
  6. * 自定义的“九宫格”——用在显示帖子详情的图片集合 解决的问题:GridView显示不全,只显示了一行的图片,比较奇怪,尝试重写GridView来解决
  7. *
  8. * @author lichao
  9. * @since 2014-10-16 16:41
  10. *
  11. */
  12. public class NoScrollGridView extends GridView {

  13.         public NoScrollGridView(Context context) {
  14.                 super(context);
  15.                 // TODO Auto-generated constructor stub
  16.         }

  17.         public NoScrollGridView(Context context, AttributeSet attrs) {
  18.                 super(context, attrs);
  19.                 // TODO Auto-generated constructor stub
  20.         }

  21.         public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) {
  22.                 super(context, attrs, defStyle);
  23.                 // TODO Auto-generated constructor stub
  24.         }

  25.         @Override
  26.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  27.                 // TODO Auto-generated method stub
  28.                 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
  29.                                 MeasureSpec.AT_MOST);
  30.                 super.onMeasure(widthMeasureSpec, expandSpec);
  31.         }

  32. }
复制代码
下来看看ListView上面Item的实体是什么样的数据结构,这就显得非常简单了。


  1. public class ItemEntity {  
  2.     private String avatar; // 用户头像URL  
  3.     private String title; // 标题  
  4.     private String content; // 内容  
  5.     private ArrayList<String> imageUrls; // 九宫格图片的URL集合  
  6.   
  7.     public ItemEntity(String avatar, String title, String content,  
  8.             ArrayList<String> imageUrls) {  
  9.         super();  
  10.         this.avatar = avatar;  
  11.         this.title = title;  
  12.         this.content = content;  
  13.         this.imageUrls = imageUrls;  
  14.     }  
  15.        ...  
  16. }  
复制代码
好了,有了ListView,那么不可避免的就是做Item上的数据适配了。继承一个BaseAdapter,代码如下,都比较简单:


  1. /**
  2. * 首页ListView的数据适配器
  3. *
  4. * @author Administrator
  5. *
  6. */
  7. public class ListItemAdapter extends BaseAdapter {

  8.         private Context mContext;
  9.         private ArrayList<ItemEntity> items;

  10.         public ListItemAdapter(Context ctx, ArrayList<ItemEntity> items) {
  11.                 this.mContext = ctx;
  12.                 this.items = items;
  13.         }

  14.         @Override
  15.         public int getCount() {
  16.                 return items == null ? 0 : items.size();
  17.         }

  18.         @Override
  19.         public Object getItem(int position) {
  20.                 return items.get(position);
  21.         }

  22.         @Override
  23.         public long getItemId(int position) {
  24.                 return position;
  25.         }

  26.         @Override
  27.         public View getView(int position, View convertView, ViewGroup parent) {
  28.                 ViewHolder holder;
  29.                 if (convertView == null) {
  30.                         holder = new ViewHolder();
  31.                         convertView = View.inflate(mContext, R.layout.item_list, null);
  32.                         holder.iv_avatar = (ImageView) convertView
  33.                                         .findViewById(R.id.iv_avatar);
  34.                         holder.tv_title = (TextView) convertView
  35.                                         .findViewById(R.id.tv_title);
  36.                         holder.tv_content = (TextView) convertView
  37.                                         .findViewById(R.id.tv_content);
  38.                         holder.gridview = (NoScrollGridView) convertView
  39.                                         .findViewById(R.id.gridview);
  40.                         convertView.setTag(holder);
  41.                 } else {
  42.                         holder = (ViewHolder) convertView.getTag();
  43.                 }
  44.                 ItemEntity itemEntity = items.get(position);
  45.                 holder.tv_title.setText(itemEntity.getTitle());
  46.                 holder.tv_content.setText(itemEntity.getContent());
  47.                 // 使用ImageLoader加载网络图片
  48.                 DisplayImageOptions options = new DisplayImageOptions.Builder()//
  49.                                 .showImageOnLoading(R.drawable.ic_launcher) // 加载中显示的默认图片
  50.                                 .showImageOnFail(R.drawable.ic_launcher) // 设置加载失败的默认图片
  51.                                 .cacheInMemory(true) // 内存缓存
  52.                                 .cacheOnDisk(true) // sdcard缓存
  53.                                 .bitmapConfig(Config.RGB_565)// 设置最低配置
  54.                                 .build();//
  55.                 ImageLoader.getInstance().displayImage(itemEntity.getAvatar(),
  56.                                 holder.iv_avatar, options);
  57.                 final ArrayList<String> imageUrls = itemEntity.getImageUrls();
  58.                 if (imageUrls == null || imageUrls.size() == 0) { // 没有图片资源就隐藏GridView
  59.                         holder.gridview.setVisibility(View.GONE);
  60.                 } else {
  61.                         holder.gridview.setAdapter(new NoScrollGridAdapter(mContext,
  62.                                         imageUrls));
  63.                 }
  64.                 // 点击回帖九宫格,查看大图
  65.                 holder.gridview.setOnItemClickListener(new OnItemClickListener() {

  66.                         @Override
  67.                         public void onItemClick(AdapterView<?> parent, View view,
  68.                                         int position, long id) {
  69.                                 // TODO Auto-generated method stub
  70.                                 imageBrower(position, imageUrls);
  71.                         }
  72.                 });
  73.                 return convertView;
  74.         }

  75.         /**
  76.          * 打开图片查看器
  77.          *
  78.          * @param position
  79.          * @param urls2
  80.          */
  81.         protected void imageBrower(int position, ArrayList<String> urls2) {
  82.                 Intent intent = new Intent(mContext, ImagePagerActivity.class);
  83.                 // 图片url,为了演示这里使用常量,一般从数据库中或网络中获取
  84.                 intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls2);
  85.                 intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);
  86.                 mContext.startActivity(intent);
  87.         }

  88.         /**
  89.          * listview组件复用,防止“卡顿”
  90.          *
  91.          * @author Administrator
  92.          *
  93.          */
  94.         class ViewHolder {
  95.                 private ImageView iv_avatar;
  96.                 private TextView tv_title;
  97.                 private TextView tv_content;
  98.                 private NoScrollGridView gridview;
  99.         }
  100. }
复制代码
这里有需要解释的地方了,看看listview上的图片处理,由于图片都是从网络获取的,为了避免图片过多造成OOM,那么这里加载图片的时候必不可少的需要做内存优化,图片的优化方式有很多,我这里采取了最简单最直接得方式,使用了开源的ImageLoader这个图片加载框架,这个框架简直是太优秀了,减少了开发者一系列不必要而且时常会出现的麻烦,关于ImageLoader并不是本篇博文需要讲解的知识,关于ImageLoader,欢迎在GitHub主页上下载,地址是https://github.com/nostra13/Android-Universal-Image-Loader,既然使用了ImageLoader这个框架,就不得不在程序上做一些初始化的操作,首先需要自定义一个全局的上下文Application类,将ImageLoader的相关属性初始化上去,直接看代码好了,见名知意:MyApplication.java




  1. public class MyApplication extends Application {
  2.         @Override
  3.         public void onCreate() {
  4.                 super.onCreate();
  5.                 DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() //
  6.                                 .showImageForEmptyUri(R.drawable.ic_launcher) //
  7.                                 .showImageOnFail(R.drawable.ic_launcher) //
  8.                                 .cacheInMemory(true) //
  9.                                 .cacheOnDisk(true) //
  10.                                 .build();//
  11.                 ImageLoaderConfiguration config = new ImageLoaderConfiguration//
  12.                 .Builder(getApplicationContext())//
  13.                                 .defaultDisplayImageOptions(defaultOptions)//
  14.                                 .discCacheSize(50 * 1024 * 1024)//
  15.                                 .discCacheFileCount(100)// 缓存一百张图片
  16.                                 .writeDebugLogs()//
  17.                                 .build();//
  18.                 ImageLoader.getInstance().init(config);
  19.         }
  20. }
复制代码
定义这个Application之后,需要在清单文件中配置一下,在Manifest.xml中的Application节点上添加:


  1. android:name="com.example.imagedemo.MyApplication"  
复制代码
  此外由于ImageLoader是网络获取图片,又需要本地sdcard缓存图片,所以需要加上一下的权限,这是Imageloader标准权限:


  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
复制代码
再看看上面的Item上数据,里面有个GridView,显然这个GridView也是需要做数据适配的,这个数据反应的是从网络加载图片,比较简单,看代码NoScrollGridAdapter.java


  1.   ......  
  2. Override  
  3. public View getView(int position, View convertView, ViewGroup parent) {  
  4.     View view = View.inflate(ctx, R.layout.item_gridview, null);  
  5.     ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);  
  6.     DisplayImageOptions options = new DisplayImageOptions.Builder()//  
  7.             .cacheInMemory(true)//  
  8.             .cacheOnDisk(true)//  
  9.             .bitmapConfig(Config.RGB_565)//  
  10.             .build();  
  11.     ImageLoader.getInstance().displayImage(imageUrls.get(position),  
  12.             imageView, options);  
  13.     return view;  
  14. }  
  15.     ......  
复制代码


http://blog.csdn.net/allen315410/article/details/40264551#


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|安卓论坛  

GMT+8, 2024-5-15 18:10 , Processed in 0.064433 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Design S!|ƽ̶

快速回复 返回顶部 返回列表