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

Android仿微信朋友圈图片查看器,第1张

概述再看文章之前,希望大家先打开自己的微信点到朋友圈中去,仔细观察是不是发现朋友圈里的有个“九宫格”的图片区域,点击图片又会跳到图片的详细查看页面,并且支持图片的滑动和缩放?这个功能是不是很常用呢?!那么

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

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

<?xml version="1.0" enCoding="utf-8"?> <relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:paddingBottom="5dp"  androID:paddingtop="5dp" >   <ImageVIEw  androID:ID="@+ID/iv_avatar"  androID:layout_wIDth="50dp"  androID:layout_height="50dp"  androID:background="@drawable/ic_launcher"  androID:scaleType="centerCrop" />   <TextVIEw  androID:ID="@+ID/tv_Title"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_marginleft="5dp"  androID:layout_toRightOf="@ID/iv_avatar"  androID:text="爷,今天心情好!"  androID:textSize="16sp" />   <TextVIEw  androID:ID="@+ID/tv_content"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_below="@+ID/tv_Title"  androID:layout_marginleft="5dp"  androID:layout_margintop="3dp"  androID:layout_toRightOf="@ID/iv_avatar"  androID:text="今天又是雾霾!"  androID:textSize="16sp" />   <com.example.imagedemo.NoScrollGrIDVIEw  androID:ID="@+ID/grIDvIEw"  androID:layout_wIDth="220dp"  androID:layout_height="wrap_content"  androID:layout_below="@ID/tv_content"  androID:layout_marginleft="5dp"  androID:layout_margintop="3dp"  androID:layout_toRightOf="@ID/iv_avatar"  androID:columnWIDth="70dp"  androID:gravity="center"  androID:horizontalSpacing="2.5dp"  androID:numColumns="3"  androID:stretchMode="columnWIDth"  androID:verticalSpacing="2.5dp" />  </relativeLayout> 

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

package com.example.imagedemo;  import androID.content.Context; import androID.util.AttributeSet; import androID.Widget.GrIDVIEw;  /**  * 自定义的“九宫格”――用在显示帖子详情的图片集合 解决的问题:GrIDVIEw显示不全,只显示了一行的图片,比较奇怪,尝试重写GrIDVIEw来解决  *  * @author lichao  * @since 2014-10-16 16:41  *  */ public class NoScrollGrIDVIEw extends GrIDVIEw {   public NoScrollGrIDVIEw(Context context) {  super(context);  // Todo auto-generated constructor stub  }   public NoScrollGrIDVIEw(Context context,AttributeSet attrs) {  super(context,attrs);  // Todo auto-generated constructor stub  }   public NoScrollGrIDVIEw(Context context,AttributeSet attrs,int defStyle) {  super(context,attrs,defStyle);  // Todo auto-generated constructor stub  }   @OverrIDe  protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  // Todo auto-generated method stub  int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);  super.onMeasure(wIDthMeasureSpec,expandSpec);  }  } 

        接下来看看ListVIEw上面Item的实体是什么样的数据结构,这就显得非常简单了。

public class ItemEntity {  private String avatar; // 用户头像URL  private String Title; // 标题  private String content; // 内容  private ArrayList<String> imageUrls; // 九宫格图片的URL集合   public ItemEntity(String avatar,String Title,String content,ArrayList<String> imageUrls) {  super();  this.avatar = avatar;  this.Title = Title;  this.content = content;  this.imageUrls = imageUrls;  }  ... } 

        好了,有了ListVIEw,那么不可避免的就是做Item上的数据适配了。继承一个BaseAdapter,代码如下,都比较简单:

/**  * 首页ListVIEw的数据适配器  *  * @author administrator  *  */ public class ListItemAdapter extends BaseAdapter {   private Context mContext;  private ArrayList<ItemEntity> items;   public ListItemAdapter(Context ctx,ArrayList<ItemEntity> items) {  this.mContext = ctx;  this.items = items;  }   @OverrIDe  public int getCount() {  return items == null ? 0 : items.size();  }   @OverrIDe  public Object getItem(int position) {  return items.get(position);  }   @OverrIDe  public long getItemID(int position) {  return position;  }   @OverrIDe  public VIEw getVIEw(int position,VIEw convertVIEw,VIEwGroup parent) {  VIEwHolder holder;  if (convertVIEw == null) {   holder = new VIEwHolder();   convertVIEw = VIEw.inflate(mContext,R.layout.item_List,null);   holder.iv_avatar = (ImageVIEw) convertVIEw    .findVIEwByID(R.ID.iv_avatar);   holder.tv_Title = (TextVIEw) convertVIEw    .findVIEwByID(R.ID.tv_Title);   holder.tv_content = (TextVIEw) convertVIEw    .findVIEwByID(R.ID.tv_content);   holder.grIDvIEw = (NoScrollGrIDVIEw) convertVIEw    .findVIEwByID(R.ID.grIDvIEw);   convertVIEw.setTag(holder);  } else {   holder = (VIEwHolder) convertVIEw.getTag();  }  ItemEntity itemEntity = items.get(position);  holder.tv_Title.setText(itemEntity.getTitle());  holder.tv_content.setText(itemEntity.getContent());  // 使用ImageLoader加载网络图片  displayImageOptions options = new displayImageOptions.Builder()//   .showImageOnLoading(R.drawable.ic_launcher) // 加载中显示的默认图片   .showImageOnFail(R.drawable.ic_launcher) // 设置加载失败的默认图片   .cacheInMemory(true) // 内存缓存   .cacheOndisk(true) // sdcard缓存   .bitmapConfig(Config.RGB_565)// 设置最低配置   .build();//  ImageLoader.getInstance().displayImage(itemEntity.getAvatar(),holder.iv_avatar,options);  final ArrayList<String> imageUrls = itemEntity.getimageUrls();  if (imageUrls == null || imageUrls.size() == 0) { // 没有图片资源就隐藏GrIDVIEw   holder.grIDvIEw.setVisibility(VIEw.GONE);  } else {   holder.grIDvIEw.setAdapter(new NoScrollGrIDAdapter(mContext,imageUrls));  }  // 点击回帖九宫格,查看大图  holder.grIDvIEw.setonItemClickListener(new OnItemClickListener() {    @OverrIDe   public voID onItemClick(AdapterVIEw<?> parent,VIEw vIEw,int position,long ID) {   // Todo auto-generated method stub   imagebrower(position,imageUrls);   }  });  return convertVIEw;  }   /**  * 打开图片查看器  *  * @param position  * @param urls2  */  protected voID imagebrower(int position,ArrayList<String> urls2) {  Intent intent = new Intent(mContext,ImagePagerActivity.class);  // 图片url,为了演示这里使用常量,一般从数据库中或网络中获取  intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS,urls2);  intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX,position);  mContext.startActivity(intent);  }   /**  * ListvIEw组件复用,防止“卡顿”  *  * @author administrator  *  */  class VIEwHolder {  private ImageVIEw iv_avatar;  private TextVIEw tv_Title;  private TextVIEw tv_content;  private NoScrollGrIDVIEw grIDvIEw;  } } 

        这里有需要解释的地方了,看看ListvIEw上的图片处理,由于图片都是从网络获取的,为了避免图片过多造成OOM,那么这里加载图片的时候必不可少的需要做内存优化,图片的优化方式有很多,我这里采取了最简单最直接得方式,使用了开源的ImageLoader这个图片加载框架,这个框架简直是太优秀了,减少了开发者一系列不必要而且时常会出现的麻烦,关于ImageLoader并不是本篇博文需要讲解的知识,关于ImageLoader,欢迎在GitHub主页上下载,地址是https://github.com/nostra13/AndroID-Universal-image-loader,既然使用了ImageLoader这个框架,就不得不在程序上做一些初始化的 *** 作,首先需要自定义一个全局的上下文Application类,将ImageLoader的相关属性初始化上去,直接看代码好了,见名知意:MyApplication.java

public class MyApplication extends Application {  @OverrIDe  public voID onCreate() {  super.onCreate();  displayImageOptions defaultoptions = new displayImageOptions.Builder() //   .showImageForEmptyUri(R.drawable.ic_launcher) //   .showImageOnFail(R.drawable.ic_launcher) //   .cacheInMemory(true) //   .cacheOndisk(true) //   .build();//  ImageLoaderConfiguration config = new ImageLoaderConfiguration//  .Builder(getApplicationContext())//   .defaultdisplayImageOptions(defaultoptions)//   .discCacheSize(50 * 1024 * 1024)//   .discCachefileCount(100)// 缓存一百张图片   .writeDeBUGLogs()//   .build();//  ImageLoader.getInstance().init(config);  } } 

       定义这个Application之后,需要在清单文件中配置一下,在Manifest.xml中的Application节点上添加:
androID:name="com.example.imagedemo.MyApplication"  
        此外由于ImageLoader是网络获取图片,又需要本地sdcard缓存图片,所以需要加上一下的权限,这是Imageloader标准权限:

<uses-permission androID:name="androID.permission.INTERNET" /> <uses-permission androID:name="androID.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission androID:name="androID.permission.ACCESS_NETWORK_STATE" /> 

       再看看上面的Item上数据,里面有个GrIDVIEw,显然这个GrIDVIEw也是需要做数据适配的,这个数据反应的是从网络加载图片,比较简单,看代码NoScrollGrIDAdapter.java

 ...... OverrIDe public VIEw getVIEw(int position,VIEwGroup parent) {  VIEw vIEw = VIEw.inflate(ctx,R.layout.item_grIDvIEw,null);  ImageVIEw imageVIEw = (ImageVIEw) vIEw.findVIEwByID(R.ID.iv_image);  displayImageOptions options = new displayImageOptions.Builder()//   .cacheInMemory(true)//   .cacheOndisk(true)//   .bitmapConfig(Config.RGB_565)//   .build();  ImageLoader.getInstance().displayImage(imageUrls.get(position),imageVIEw,options);  return vIEw; }  ...... 

         这样,所有的数据适配就做好了,接下来就需要做图片查看器了,当我们点击ListVIEw上Item里的“九宫格”――NoScrollGrIDVIEw的某张图片的时候,需要把这个图片的url传给一个图片查看器,图片查看器里会根据传递进来的url去网络加载这张图片,那么其实图片查看器就是一个新的单独的Activity,这个Activity会包含一个VIEwPager,用来管理多张图片的查看。image_detail_pager.xml

<?xml version="1.0" enCoding="utf-8"?> <FrameLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent" >   <com.example.imagedemo.HackyVIEwPager  androID:ID="@+ID/pager"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:background="@androID:color/black" />   <TextVIEw  androID:ID="@+ID/indicator"  androID:layout_wIDth="match_parent"  androID:layout_height="wrap_content"  androID:layout_gravity="bottom"  androID:background="@androID:color/transparent"  androID:gravity="center"  androID:text="@string/vIEwpager_indicator"  androID:textcolor="@androID:color/white"  androID:textSize="18sp" />  </FrameLayout> 

HackyVIEwPager.java

public class HackyVIEwPager extends VIEwPager {   private static final String TAG = "HackyVIEwPager";   public HackyVIEwPager(Context context) {  super(context);  }   public HackyVIEwPager(Context context,attrs);  }   @OverrIDe  public boolean onIntercepttouchEvent(MotionEvent ev) {  try {   return super.onIntercepttouchEvent(ev);  } catch (IllegalArgumentException e) {   // 不理会   Log.e(TAG,"Hacky vIEwpager error1");   return false;  } catch (Arrayindexoutofboundsexception e) {   // 不理会   Log.e(TAG,"Hacky vIEwpager error2");   return false;  }  }  } 

ImagePagerActivity.java

/**  * 图片查看器  */ public class ImagePagerActivity extends FragmentActivity {  private static final String STATE_position = "STATE_position";  public static final String EXTRA_IMAGE_INDEX = "image_index";  public static final String EXTRA_IMAGE_URLS = "image_urls";   private HackyVIEwPager mPager;  private int pagerposition;  private TextVIEw indicator;   @OverrIDe  public voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.image_detail_pager);   pagerposition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX,0);  ArrayList<String> urls = getIntent().getStringArrayListExtra(   EXTRA_IMAGE_URLS);   mPager = (HackyVIEwPager) findVIEwByID(R.ID.pager);  ImagePagerAdapter mAdapter = new ImagePagerAdapter(   getSupportFragmentManager(),urls);  mPager.setAdapter(mAdapter);  indicator = (TextVIEw) findVIEwByID(R.ID.indicator);   CharSequence text = getString(R.string.vIEwpager_indicator,1,mPager   .getAdapter().getCount());  indicator.setText(text);  // 更新下标  mPager.setonPagechangelistener(new OnPagechangelistener() {    @OverrIDe   public voID onPageScrollStateChanged(int arg0) {   }    @OverrIDe   public voID onPageScrolled(int arg0,float arg1,int arg2) {   }    @OverrIDe   public voID onPageSelected(int arg0) {   CharSequence text = getString(R.string.vIEwpager_indicator,arg0 + 1,mPager.getAdapter().getCount());   indicator.setText(text);   }   });  if (savedInstanceState != null) {   pagerposition = savedInstanceState.getInt(STATE_position);  }   mPager.setCurrentItem(pagerposition);  }   @OverrIDe  public voID onSaveInstanceState(Bundle outState) {  outState.putInt(STATE_position,mPager.getCurrentItem());  }   private class ImagePagerAdapter extends FragmentStatePagerAdapter {   public ArrayList<String> fileList;   public ImagePagerAdapter(FragmentManager fm,ArrayList<String> fileList) {   super(fm);   this.fileList = fileList;  }   @OverrIDe  public int getCount() {   return fileList == null ? 0 : fileList.size();  }   @OverrIDe  public Fragment getItem(int position) {   String url = fileList.get(position);   return ImageDetailFragment.newInstance(url);  }   } } 

          已知图片查看的界面是继承自FragmentActivity的,所以支持显示的界面必须需要Fragment来实现,那么就自定义个Frangment吧,用这个Fragment来从url中获取图片资源,显示图片。image_detail_fragment.xml

<?xml version="1.0" enCoding="utf-8"?> <FrameLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:background="@androID:color/black" >   <ImageVIEw  androID:ID="@+ID/image"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:adjustVIEwBounds="true"  androID:contentDescription="@string/app_name"  androID:scaleType="centerCrop" />   <Progressbar  androID:ID="@+ID/loading"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_gravity="center"  androID:visibility="gone" />  </FrameLayout> 

ImageDetailFragment.java

/**  * 单张图片显示Fragment  */ public class ImageDetailFragment extends Fragment {  private String mImageUrl;  private ImageVIEw mImageVIEw;  private Progressbar progressbar;  private PhotoVIEwAttacher mAttacher;   public static ImageDetailFragment newInstance(String imageUrl) {  final ImageDetailFragment f = new ImageDetailFragment();   final Bundle args = new Bundle();  args.putString("url",imageUrl);  f.setArguments(args);   return f;  }   @OverrIDe  public voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  mImageUrl = getArguments() != null ? getArguments().getString("url")   : null;  }   @OverrIDe  public VIEw onCreateVIEw(LayoutInflater inflater,VIEwGroup container,Bundle savedInstanceState) {  final VIEw v = inflater.inflate(R.layout.image_detail_fragment,container,false);  mImageVIEw = (ImageVIEw) v.findVIEwByID(R.ID.image);  mAttacher = new PhotoVIEwAttacher(mImageVIEw);   mAttacher.setonPhotoTapListener(new OnPhotoTapListener() {    @OverrIDe   public voID onPhotoTap(VIEw arg0,float arg2) {   getActivity().finish();   }  });   progressbar = (Progressbar) v.findVIEwByID(R.ID.loading);  return v;  }   @OverrIDe  public voID onActivityCreated(Bundle savedInstanceState) {  super.onActivityCreated(savedInstanceState);   ImageLoader.getInstance().displayImage(mImageUrl,mImageVIEw,new SimpleImageLoadingListener() {    @OverrIDe    public voID onLoadingStarted(String imageUri,VIEw vIEw) {    progressbar.setVisibility(VIEw.VISIBLE);    }     @OverrIDe    public voID onLoadingFailed(String imageUri,FailReason failReason) {    String message = null;    switch (failReason.getType()) {    case IO_ERROR:     message = "下载错误";     break;    case DECoding_ERROR:     message = "图片无法显示";     break;    case NETWORK_DENIED:     message = "网络有问题,无法下载";     break;    case OUT_OF_MEMORY:     message = "图片太大无法显示";     break;    case UNKNowN:     message = "未知的错误";     break;    }    Toast.makeText(getActivity(),message,Toast.LENGTH_SHORT).show();    progressbar.setVisibility(VIEw.GONE);    }     @OverrIDe    public voID onLoadingComplete(String imageUri,Bitmap loadedImage) {    progressbar.setVisibility(VIEw.GONE);    mAttacher.update();    }   });  } } 

         写到这里,此篇博文也宣告结束了。需要提出的是,我这里的图片查看器实现的图片的缩放效果使用的是开源组件PhotoVIEw,关于PhotoVIEw的github项目地址在这里,https://github.com/chrisbanes/PhotoVIEw 需要点进去这个项目的网址,去下载源码,将源码全部拷贝到项目中来,使用也是相当方便的,demo如下:

ImageVIEw mImageVIEw; PhotoVIEwAttacher mAttacher;  @OverrIDe public voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.activity_main);   // Any implementation of ImageVIEw can be used!  mImageVIEw = (ImageVIEw) findVIEwByID(R.ID.iv_photo);   // Set the Drawable displayed  Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);  mImageVIEw.setimageDrawable(bitmap);   // Attach a PhotoVIEwAttacher,which takes care of all of the zooming functionality.  mAttacher = new PhotoVIEwAttacher(mImageVIEw); }   // If you later call mImageVIEw.setimageDrawable/setimageBitmap/setimageResource/etc then you just need to call attacher.update(); 

         刚开始这个图片查看器是我自己自定义view来实现的,其实需要实现图片的手势识别+多点触控+缩放,是可以使用矩阵Matrix来实现的,只不过这样显得特别的麻烦不说,而且极易出现BUG,这对于某些“急功近利”的项目来说,是个不好的兆头。所以,我这里摒弃了我用Matrix自定义的效果,改用github大牛为我们写好的开源组件,这样效率就上去了,大家也可以用Matrix自己去实现一下图片的多点触摸缩放的效果,关于Matrix的学习,请参加我以前的博文,AndroID自定义控件――3D画廊和图像矩阵。其实关于androID上的图片缩放真没什么其它的方式,唯一能使用的还是Matrix这个类,不信先来瞧瞧Github大牛写的开源组件PhotoVIEw是怎么实现的,查看以下部分源码:

// These are set so we don't keep allocating them on the heap  private final Matrix mBaseMatrix = new Matrix();  private final Matrix mDrawMatrix = new Matrix();  private final Matrix mSuppMatrix = new Matrix();  private final RectF mdisplayRect = new RectF();  private final float[] mMatrixValues = new float[9]; 
/**  * Set's the ImageVIEw's ScaleType to Matrix.  */  private static voID setimageVIEwScaleTypeMatrix(ImageVIEw imageVIEw) {  /**  * PhotoVIEw sets it's own ScaleType to Matrix,then diverts all calls  * setScaleType to this.setScaleType automatically.  */  if (null != imageVIEw && !(imageVIEw instanceof IPhotoVIEw)) {   if (!ScaleType.MATRIX.equals(imageVIEw.getScaleType())) {   imageVIEw.setScaleType(ScaleType.MATRIX);   }  }  } 

        以上只是PhotoVIEw的部分源码,一目了然的发现它的实现也是基于Matrix的,时间与篇幅的局限性,大家需要更好的了解PhotoVIEw的实现的话,就下载它的源码查看吧,要理解大神的想法是需要一些扎实的基础,关于PhotoVIEw的具体实现细节,我也弄不太明白,可能是我对Matrix了解的不深刻吧,希望以后加强学习,也希望以后跟你们交流学习,共同进步!

本文转载:http://blog.csdn.net/allen315410/article/details/40264551

总结

以上是内存溢出为你收集整理的Android仿微信朋友圈图片查看器全部内容,希望文章能够帮你解决Android仿微信朋友圈图片查看器所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1142071.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存