国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

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

2019-12-12 06:24:26
字體:
來源:轉載
供稿:網友

再看文章之前,希望大家先打開自己的微信點到朋友圈中去,仔細觀察是不是發現朋友圈里的有個“九宮格”的圖片區域,點擊圖片又會跳到圖片的詳細查看頁面,并且支持圖片的滑動和縮放?這個功能是不是很常用呢?!那么我今天正好做了這個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, View convertView, 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, AttributeSet attrs) {  super(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 arg1, 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, View view,     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, View view,     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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 台湾省| 绍兴市| 革吉县| 望谟县| 乌拉特前旗| 开原市| 广安市| 红安县| 德安县| 丹巴县| 呼玛县| 衡南县| 正蓝旗| 阿巴嘎旗| 铜陵市| 余姚市| 安吉县| 新绛县| 石泉县| 翁牛特旗| 东台市| 富顺县| 鹤峰县| 东阳市| 卢龙县| 会东县| 甘泉县| 榆社县| 义乌市| 安吉县| 邵武市| 木里| 隆尧县| 古浪县| 城步| 宜昌市| 阿城市| 高邑县| 雷波县| 高台县| 天等县|