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

转载请注明出处:http://blog.csdn.net/allen315410/article/details/40264551

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

主页ListView的效果:                                  点击九宫格图片跳转到大图                                     多点触控,缩放图片

        

      效果嘛,将就着看吧!实在看不明白就想想微信朋友圈,或者拖到下方,点击下载源码!这里,首先分析一下主界面吧,布局都是很简单的,主界面仅仅就是一个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.   
  8.     <ImageView  
  9.         android:id="@+id/iv_avatar"  
  10.         android:layout_width="50dp"  
  11.         android:layout_height="50dp"  
  12.         android:background="@drawable/ic_launcher"  
  13.         android:scaleType="centerCrop" />  
  14.   
  15.     <TextView  
  16.         android:id="@+id/tv_title"  
  17.         android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_marginLeft="5dp"  
  20.         android:layout_toRightOf="@id/iv_avatar"  
  21.         android:text="爷,今天心情好!"  
  22.         android:textSize="16sp" />  
  23.   
  24.     <TextView  
  25.         android:id="@+id/tv_content"  
  26.         android:layout_width="wrap_content"  
  27.         android:layout_height="wrap_content"  
  28.         android:layout_below="@+id/tv_title"  
  29.         android:layout_marginLeft="5dp"  
  30.         android:layout_marginTop="3dp"  
  31.         android:layout_toRightOf="@id/iv_avatar"  
  32.         android:text="今天又是雾霾!"  
  33.         android:textSize="16sp" />  
  34.   
  35.     <com.example.imagedemo.NoScrollGridView  
  36.         android:id="@+id/gridview"  
  37.         android:layout_width="220dp"  
  38.         android:layout_height="wrap_content"  
  39.         android:layout_below="@id/tv_content"  
  40.         android:layout_marginLeft="5dp"  
  41.         android:layout_marginTop="3dp"  
  42.         android:layout_toRightOf="@id/iv_avatar"  
  43.         android:columnWidth="70dp"  
  44.         android:gravity="center"  
  45.         android:horizontalSpacing="2.5dp"  
  46.         android:numColumns="3"  
  47.         android:stretchMode="columnWidth"  
  48.         android:verticalSpacing="2.5dp" />  
  49.   
  50. </RelativeLayout> 


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

  1. package com.example.imagedemo;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.widget.GridView;  
  6.   
  7. /** 
  8.  * 自定义的“九宫格”——用在显示帖子详情的图片集合 解决的问题:GridView显示不全,只显示了一行的图片,比较奇怪,尝试重写GridView来解决 
  9.  *  
  10.  * @author lichao 
  11.  * @since 2014-10-16 16:41 
  12.  *  
  13.  */  
  14. public class NoScrollGridView extends GridView {  
  15.   
  16.     public NoScrollGridView(Context context) {  
  17.         super(context);  
  18.         // TODO Auto-generated constructor stub  
  19.     }  
  20.   
  21.     public NoScrollGridView(Context context, AttributeSet attrs) {  
  22.         super(context, attrs);  
  23.         // TODO Auto-generated constructor stub  
  24.     }  
  25.   
  26.     public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) {  
  27.         super(context, attrs, defStyle);  
  28.         // TODO Auto-generated constructor stub  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  33.         // TODO Auto-generated method stub  
  34.         int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  
  35.                 MeasureSpec.AT_MOST);  
  36.         super.onMeasure(widthMeasureSpec, expandSpec);  
  37.     }  
  38.   


  接下来看看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.        ...  

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

  1. /** 
  2.  * 首页ListView的数据适配器 
  3.  *  
  4.  * @author Administrator 
  5.  *  
  6.  */  
  7. public class ListItemAdapter extends BaseAdapter {  
  8.   
  9.     private Context mContext;  
  10.     private ArrayList<ItemEntity> items;  
  11.   
  12.     public ListItemAdapter(Context ctx, ArrayList<ItemEntity> items) {  
  13.         this.mContext = ctx;  
  14.         this.items = items;  
  15.     }  
  16.   
  17.     @Override  
  18.     public int getCount() {  
  19.         return items == null ? 0 : items.size();  
  20.     }  
  21.   
  22.     @Override  
  23.     public Object getItem(int position) {  
  24.         return items.get(position);  
  25.     }  
  26.   
  27.     @Override  
  28.     public long getItemId(int position) {  
  29.         return position;  
  30.     }  
  31.   
  32.     @Override  
  33.     public View getView(int position, View convertView, ViewGroup parent) {  
  34.         ViewHolder holder; 

  1.    if (convertView == null) {  
  2.             holder = new ViewHolder();  
  3.             convertView = View.inflate(mContext, R.layout.item_list, null);  
  4.             holder.iv_avatar = (ImageView) convertView  
  5.                     .findViewById(R.id.iv_avatar);  
  6.             holder.tv_title = (TextView) convertView  
  7.                     .findViewById(R.id.tv_title);  
  8.             holder.tv_content = (TextView) convertView  
  9.                     .findViewById(R.id.tv_content);  
  10.             holder.gridview = (NoScrollGridView) convertView  
  11.                     .findViewById(R.id.gridview);  
  12.             convertView.setTag(holder);  
  13.         } else {  
  14.             holder = (ViewHolder) convertView.getTag();  
  15.         }  
  16.         ItemEntity itemEntity = items.get(position);  
  17.         holder.tv_title.setText(itemEntity.getTitle());  
  18.         holder.tv_content.setText(itemEntity.getContent());  
  19.         // 使用ImageLoader加载网络图片  
  20.         DisplayImageOptions options = new DisplayImageOptions.Builder()//  
  21.                 .showImageOnLoading(R.drawable.ic_launcher) // 加载中显示的默认图片  
  22.                 .showImageOnFail(R.drawable.ic_launcher) // 设置加载失败的默认图片  
  23.                 .cacheInMemory(true// 内存缓存  
  24.                 .cacheOnDisk(true// sdcard缓存  
  25.                 .bitmapConfig(Config.RGB_565)// 设置最低配置  
  26.                 .build();//  
  27.         ImageLoader.getInstance().displayImage(itemEntity.getAvatar(),  
  28.                 holder.iv_avatar, options);  
  29.         final ArrayList<String> imageUrls = itemEntity.getImageUrls();  
  30.         if (imageUrls == null || imageUrls.size() == 0) { // 没有图片资源就隐藏GridView  
  31.             holder.gridview.setVisibility(View.GONE);  
  32.         } else {  
  33.             holder.gridview.setAdapter(new NoScrollGridAdapter(mContext,  
  34.                     imageUrls));  
  35.         }  
  36.         // 点击回帖九宫格,查看大图  
  37.         holder.gridview.setOnItemClickListener(new OnItemClickListener() {  
  38.   
  39.             @Override  
  40.             public void onItemClick(AdapterView<?> parent, View view,  
  41.                     int position, long id) {  
  42.                 // TODO Auto-generated method stub  
  43.                 imageBrower(position, imageUrls);  
  44.             }  
  45.         });  
  46.         return convertView;  
  47.     }  
  48.   
  49.     /** 
  50.      * 打开图片查看器 
  51.      *  
  52.      * @param position 
  53.      * @param urls2 
  54.      */  
  55.     protected void imageBrower(int position, ArrayList<String> urls2) {  
  56.         Intent intent = new Intent(mContext, ImagePagerActivity.class);  
  57.         // 图片url,为了演示这里使用常量,一般从数据库中或网络中获取  
  58.         intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls2);  
  59.         intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);  
  60.         mContext.startActivity(intent);  
  61.     }  
  62.   
  63.     /** 
  64.      * listview组件复用,防止“卡顿” 
  65.      *  
  66.      * @author Administrator 
  67.      *  
  68.      */  
  69.     class ViewHolder {  
  70.         private ImageView iv_avatar;  
  71.         private TextView tv_title;  
  72.         private TextView tv_content;  
  73.         private NoScrollGridView gridview;  
  74.     }  

    这里有需要解释的地方了,看看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.     }  

     定义这个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.     ...... 

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

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <com.example.imagedemo.HackyViewPager  
  7.         android:id="@+id/pager"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         android:background="@android:color/black" />  
  11.   
  12.     <TextView  
  13.         android:id="@+id/indicator"  
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:layout_gravity="bottom"  
  17.         android:background="@android:color/transparent"  
  18.         android:gravity="center"  
  19.         android:text="@string/viewpager_indicator"  
  20.         android:textColor="@android:color/white"  
  21.         android:textSize="18sp" />  
  22.   
  23. </FrameLayout>  
HackyViewPager.java
  1. public class HackyViewPager extends ViewPager {  
  2.   
  3.     private static final String TAG = "HackyViewPager";  
  4.   
  5.     public HackyViewPager(Context context) {  
  6.         super(context);  
  7.     }  
  8.   
  9.     public HackyViewPager(Context context, AttributeSet attrs) {  
  10.         super(context, attrs);  
  11.     }  
  12.   
  13.     @Override  
  14.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  15.         try {  
  16.             return super.onInterceptTouchEvent(ev);  
  17.         } catch (IllegalArgumentException e) {  
  18.             // 不理会  
  19.             Log.e(TAG, "hacky viewpager error1");  
  20.             return false;  
  21.         } catch (ArrayIndexOutOfBoundsException e) {  
  22.             // 不理会  
  23.             Log.e(TAG, "hacky viewpager error2");  
  24.             return false;  
  25.         }  
  26.     }  
  27.   
  28. }  
ImagePagerActivity.java
  1. /** 
  2.  * 图片查看器 
  3.  */  
  4. public class ImagePagerActivity extends FragmentActivity {  
  5.     private static final String STATE_POSITION = "STATE_POSITION";  
  6.     public static final String EXTRA_IMAGE_INDEX = "image_index";  
  7.     public static final String EXTRA_IMAGE_URLS = "image_urls";  
  8.   
  9.     private HackyViewPager mPager;  
  10.     private int pagerPosition;  
  11.     private TextView indicator;  
  12.   
  13.     @Override  
  14.     public void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.image_detail_pager);  
  17.   
  18.         pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0);  
  19.         ArrayList<String> urls = getIntent().getStringArrayListExtra(  
  20.                 EXTRA_IMAGE_URLS);  
  21.   
  22.         mPager = (HackyViewPager) findViewById(R.id.pager);  
  23.         ImagePagerAdapter mAdapter = new ImagePagerAdapter(  
  24.                 getSupportFragmentManager(), urls);  
  25.         mPager.setAdapter(mAdapter);  
  26.         indicator = (TextView) findViewById(R.id.indicator);  
  27.   
  28.         CharSequence text = getString(R.string.viewpager_indicator, 1, mPager  
  29.                 .getAdapter().getCount());  
  30.         indicator.setText(text);  
  31.         // 更新下标  
  32.         mPager.setOnPageChangeListener(new OnPageChangeListener() {  
  33.   
  34.             @Override  
  35.             public void onPageScrollStateChanged(int arg0) {  
  36.             }  
  37.   
  38.             @Override  
  39.             public void onPageScrolled(int arg0, float arg1, int arg2) {  
  40.             }  
  41.   
  42.             @Override  
  43.             public void onPageSelected(int arg0) {  
  44.                 CharSequence text = getString(R.string.viewpager_indicator,  
  45.                         arg0 + 1, mPager.getAdapter().getCount());  
  46.                 indicator.setText(text);  
  47.             }  
  48.   
  49.         });  
  50.         if (savedInstanceState != null) {  
  51.             pagerPosition = savedInstanceState.getInt(STATE_POSITION);  
  52.         }  
  53.   
  54.         mPager.setCurrentItem(pagerPosition);  
  55.     }  
  56.   
  57.     @Override  
  58.     public void onSaveInstanceState(Bundle outState) {  
  59.         outState.putInt(STATE_POSITION, mPager.getCurrentItem());  
  60.     }  
  61.   
  62.     private class ImagePagerAdapter extends FragmentStatePagerAdapter {  
  63.   
  64.         public ArrayList<String> fileList;  
  65.   
  66.         public ImagePagerAdapter(FragmentManager fm, ArrayList<String> fileList) {  
  67.             super(fm);  
  68.             this.fileList = fileList;  
  69.         }  
  70.   
  71.         @Override  
  72.         public int getCount() {  
  73.             return fileList == null ? 0 : fileList.size();  
  74.         }  
  75.   
  76.         @Override  
  77.         public Fragment getItem(int position) {  
  78.             String url = fileList.get(position);  
  79.             return ImageDetailFragment.newInstance(url);  
  80.         }  
  81.   
  82.     }  
  83. }  

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

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="@android:color/black" >  
  6.   
  7.     <ImageView  
  8.         android:id="@+id/image"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         android:adjustViewBounds="true"  
  12.         android:contentDescription="@string/app_name"  
  13.         android:scaleType="centerCrop" />  
  14.   
  15.     <ProgressBar  
  16.         android:id="@+id/loading"  
  17.         android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_gravity="center"  
  20.         android:visibility="gone" />  
  21.   
  22. </FrameLayout>  
ImageDetailFragment.java
  1. /** 
  2.  * 单张图片显示Fragment 
  3.  */  
  4. public class ImageDetailFragment extends Fragment {  
  5.     private String mImageUrl;  
  6.     private ImageView mImageView;  
  7.     private ProgressBar progressBar;  
  8.     private PhotoViewAttacher mAttacher;  
  9.   
  10.     public static ImageDetailFragment newInstance(String imageUrl) {  
  11.         final ImageDetailFragment f = new ImageDetailFragment();  
  12.   
  13.         final Bundle args = new Bundle();  
  14.         args.putString("url", imageUrl);  
  15.         f.setArguments(args);  
  16.   
  17.         return f;  
  18.     }  
  19.   
  20.     @Override  
  21.     public void onCreate(Bundle savedInstanceState) {  
  22.         super.onCreate(savedInstanceState);  
  23.         mImageUrl = getArguments() != null ? getArguments().getString("url")  
  24.                 : null;  
  25.     }  
  26.   
  27.     @Override  
  28.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  29.             Bundle savedInstanceState) {  
  30.         final View v = inflater.inflate(R.layout.image_detail_fragment,  
  31.                 container, false);  
  32.         mImageView = (ImageView) v.findViewById(R.id.image);  
  33.         mAttacher = new PhotoViewAttacher(mImageView);  
  34.   
  35.         mAttacher.setOnPhotoTapListener(new OnPhotoTapListener() {  
  36.   
  37.             @Override  
  38.             public void onPhotoTap(View arg0, float arg1, float arg2) {  
  39.                 getActivity().finish();  
  40.             }  
  41.         });  
  42.   
  43.         progressBar = (ProgressBar) v.findViewById(R.id.loading);  
  44.         return v;  
  45.     }  
  46.   
  47.     @Override  
  48.     public void onActivityCreated(Bundle savedInstanceState) {  
  49.         super.onActivityCreated(savedInstanceState);  
  50.   
  51.         ImageLoader.getInstance().displayImage(mImageUrl, mImageView,  
  52.                 new SimpleImageLoadingListener() {  
  53.                     @Override  
  54.                     public void onLoadingStarted(String imageUri, View view) {  
  55.                         progressBar.setVisibility(View.VISIBLE);  
  56.                     }  
  57.   
  58.                     @Override  
  59.                     public void onLoadingFailed(String imageUri, View view,  
  60.                             FailReason failReason) {  
  61.                         String message = null;  
  62.                         switch (failReason.getType()) {  
  63.                         case IO_ERROR:  
  64.                             message = "下载错误";  
  65.                             break;  
  66.                         case DECODING_ERROR:  
  67.                             message = "图片无法显示";  
  68.                             break;  
  69.                         case NETWORK_DENIED:  
  70.                             message = "网络有问题,无法下载";  
  71.                             break;  
  72.                         case OUT_OF_MEMORY:  
  73.                             message = "图片太大无法显示";  
  74.                             break;  
  75.                         case UNKNOWN:  
  76.                             message = "未知的错误";  
  77.                             break;  
  78.                         }  
  79.                         Toast.makeText(getActivity(), message,  
  80.                                 Toast.LENGTH_SHORT).show();  
  81.                         progressBar.setVisibility(View.GONE);  
  82.                     }  
  83.   
  84.                     @Override  
  85.                     public void onLoadingComplete(String imageUri, View view,  
  86.                             Bitmap loadedImage) {  
  87.                         progressBar.setVisibility(View.GONE);  
  88.                         mAttacher.update();  
  89.                     }  
  90.                 });  
  91.     }  
  92. }  

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

  1. ImageView mImageView;  
  2. PhotoViewAttacher mAttacher;  
  3.   
  4. @Override  
  5. public void onCreate(Bundle savedInstanceState) {  
  6.     super.onCreate(savedInstanceState);  
  7.     setContentView(R.layout.activity_main);  
  8.   
  9.     // Any implementation of ImageView can be used!  
  10.     mImageView = (ImageView) findViewById(R.id.iv_photo);  
  11.   
  12.     // Set the Drawable displayed  
  13.     Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);  
  14.     mImageView.setImageDrawable(bitmap);  
  15.   
  16.     // Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.  
  17.     mAttacher = new PhotoViewAttacher(mImageView);  
  18. }  
  19.   
  20.   
  21. // If you later call mImageView.setImageDrawable/setImageBitmap/setImageResource/etc then you just need to call  
  22. attacher.update();  

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

  1. // These are set so we don't keep allocating them on the heap  
  2.     private final Matrix mBaseMatrix = new Matrix();  
  3.     private final Matrix mDrawMatrix = new Matrix();  
  4.     private final Matrix mSuppMatrix = new Matrix();  
  5.     private final RectF mDisplayRect = new RectF();  
  6.     private final float[] mMatrixValues = new float[9];  
  1. /** 
  2.     * Set's the ImageView's ScaleType to Matrix. 
  3.     */  
  4.    private static void setImageViewScaleTypeMatrix(ImageView imageView) {  
  5.        /** 
  6.         * PhotoView sets it's own ScaleType to Matrix, then diverts all calls 
  7.         * setScaleType to this.setScaleType automatically. 
  8.         */  
  9.        if (null != imageView && !(imageView instanceof IPhotoView)) {  
  10.            if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {  
  11.                imageView.setScaleType(ScaleType.MATRIX);  
  12.            }  
  13.        }  
  14.    }  
        以上只是PhotoView的部分源码,一目了然的发现它的实现也是基于Matrix的,时间与篇幅的局限性,大家需要更好的了解PhotoView的实现的话,就下载它的源码查看吧,要理解大神的想法是需要一些扎实的基础,关于PhotoView的具体实现细节,我也弄不太明白,可能是我对Matrix了解的不深刻吧,希望以后加强学习,也希望以后跟你们交流学习,共同进步!


源码请在这里下载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Android仿微信朋友圈图片查看功能,可以按照以下步骤进行: 1. 首先,需要使用一个RecyclerView来展示朋友圈的列表,每个朋友圈项包含了图片的缩略图、文字内容和评论等信息。 2. 当用户点击某个朋友圈项时,需要跳转到一个新的Activity或者Fragment来显示该朋友圈的详细内容。 3. 在新的界面中,可以使用ViewPager来展示朋友圈中的图片。ViewPager的每一页对应一张图片,并实现左右滑动切换图片的功能。 4. 对于图片的加载,可以使用一个图片加载库如Glide或Picasso来加载图片,避免OOM(Out of Memory)的问题。 5. 为了更好的用户体验,可以在ViewPager上添加一个类似于微信图片预览效果,即当用户点击某张图片时,可以全屏显示,并支持缩放、双击放大、手势滑动等功能。 6. 为了保证性能和流畅度,可以使用一些优化技巧,如图片的压缩、缓存、异步加载等。 7. 如果需要支持多张图片的查看,可以使用PhotoView或类似的第三方库来实现,它可以显示多张图片,并支持手势操作。 8. 最后,为了提高用户体验,可以加入一些其他功能,如显示图片的点赞数和评论数、支持多种分享方式、图片保存等。 通过以上步骤的实现,就可以实现Android仿微信朋友圈图片查看的功能了。这样用户就可以在朋友圈列表中预览图片,点击后再进行详细查看和操作,提高了用户的交互体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值