Android照片牆加強版,使用ViewPager實現畫廊效果
特此宣告:本文為轉載文章!尊重原創的勞動果實,嚴禁剽竊
本文轉載於: http://blog.csdn.net/guolin_blog/article/details/12646775
出自於:【郭霖的部落格】
記得關於照片牆的文章我已經寫過好幾篇了,有最基本的照片牆,有瀑布流模式的照片牆,後來又在瀑布流的基礎之上加入了檢視大圖和多點觸控縮放的功能。總體來說,照片牆這個Demo在這幾篇文章的改進中已經變得較為完善了,本想關於這個功能的系列到此為止,但有朋友跟我反應,覺得在檢視大圖的時候最好能通過左右滑動來瀏覽前後的圖片。恩,確實,好像比較高階的一些應用都有這樣的效果,那麼本篇文章中我們來繼續對照片牆這個Demo進行改進,讓它變得更加高階大氣上檔次!
整理了一下思路,感覺自己去實現一套通過左右滑動來切換圖片的功能非常不划算,需要編寫不少的程式碼。這裡為了要讓實現簡單化,我們準備使用Android提供的ViewPager來完成這個功能。
ViewPager的基本用法我就不在本文中介紹了,如果還不瞭解的朋友可以到王鵬兄那裡先學習一下 http://blog.csdn.net/wangjinyu501/article/details/8169924 。
另外,本篇文章的程式碼是完全在之前文章的基礎上進行開發的,所以如果你還沒有看過我前面所寫的關於照片牆的文章,建議先去閱讀一下 Android瀑布流照片牆實現,體驗不規則排列的美感 和 Android多點觸控技術實戰,自由地對圖片進行縮放和移動 這兩篇文章。
下面就讓我們開始動手吧,開啟PhotoWallFallsDemo這個專案,首先修改image_details.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.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
<TextView
android:id="@+id/page_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:textColor="#fff"
android:textSize="18sp" />
</RelativeLayout>
這裡我們在佈局檔案中放置了兩個控制元件,ViewPager和TextView,其中ViewPager自然是用來管理所有的圖片的了,而TextView則是用於顯示當前圖片的頁數以及總頁數。
然後新建一個zoom_image_layout.xml,在這裡放入ZoomImageView控制元件,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<com.example.photowallfallsdemo.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/zoom_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" >
</com.example.photowallfallsdemo.ZoomImageView>
接下來修改ImageDetailsActivity中的程式碼,在這裡去實現ViewPager的具體功能,程式碼如下所示:
public class ImageDetailsActivity extends Activity implements OnPageChangeListener {
/**
* 用於管理圖片的滑動
*/
private ViewPager viewPager;
/**
* 顯示當前圖片的頁數
*/
private TextView pageText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.image_details);
int imagePosition = getIntent().getIntExtra("image_position", 0);
pageText = (TextView) findViewById(R.id.page_text);
viewPager = (ViewPager) findViewById(R.id.view_pager);
ViewPagerAdapter adapter = new ViewPagerAdapter();
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(imagePosition);
viewPager.setOnPageChangeListener(this);
// 設定當前的頁數和總頁數
pageText.setText((imagePosition + 1) + "/" + Images.imageUrls.length);
}
/**
* ViewPager的介面卡
*
* @author guolin
*/
class ViewPagerAdapter extends PagerAdapter {
@Override
public Object instantiateItem(ViewGroup container, int position) {
String imagePath = getImagePath(Images.imageUrls[position]);
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
if (bitmap == null) {
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.empty_photo);
}
View view = LayoutInflater.from(ImageDetailsActivity.this).inflate(
R.layout.zoom_image_layout, null);
ZoomImageView zoomImageView = (ZoomImageView) view
.findViewById(R.id.zoom_image_view);
zoomImageView.setImageBitmap(bitmap);
container.addView(view);
return view;
}
@Override
public int getCount() {
return Images.imageUrls.length;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
}
/**
* 獲取圖片的本地儲存路徑。
*
* @param imageUrl
* 圖片的URL地址。
* @return 圖片的本地儲存路徑。
*/
private String getImagePath(String imageUrl) {
int lastSlashIndex = imageUrl.lastIndexOf("/");
String imageName = imageUrl.substring(lastSlashIndex + 1);
String imageDir = Environment.getExternalStorageDirectory().getPath()
+ "/PhotoWallFalls/";
File file = new File(imageDir);
if (!file.exists()) {
file.mkdirs();
}
String imagePath = imageDir + imageName;
return imagePath;
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int currentPage) {
// 每當頁數發生改變時重新設定一遍當前的頁數和總頁數
pageText.setText((currentPage + 1) + "/" + Images.imageUrls.length);
}
}
這個類也是實現滑動切換圖片功能最主要的一個類了,由於ViewPager的用法並不複雜,所以這個類的程式碼也不多,下面我們來仔細地分析一下。
首先在onCreate()方法中要去載入我們剛剛修改的image_details.xml佈局,然後要從Intent中取出當前要展示的那張圖片的位置。接下來通過findViewById()方法獲取到ViewPager和TextView控制元件的例項,並建立了一個ViewPagerAdapter物件作為ViewPager的介面卡,之後去呼叫setCurrentItem()方法來設定當前顯示的是哪一張圖片。
那麼這個ViewPagerAdapter又是什麼呢?可以看到,它是一個繼承了PagerAdapter的介面卡,是專門用於在ViewPager中使用的。一般情況下我們都需要至少去重寫PagerAdapter中的instantiateItem()、getCount()、isViewFromObject()和destroyItem()這四個方法。在instantiateItem()方法中,我們根據圖片的位置獲取到了圖片對應的儲存路徑,然後呼叫BitmapFactory的解析方法將這張圖片解析成一個Bitmap物件,接著例項化zoom_image_layout.xml這個佈局,並獲取其中的ZoomImageView控制元件,然後把Bitmap物件設定進去。在getCount()方法,只是簡單地返回了一共有多少張圖片。isViewFromObject()方法比較簡單,就是判斷兩個引數是否相等就好。而destroyItem()方法中,則是要把應該銷燬的View物件回收掉,以防止圖片過多導致OOM出現。
另外,這裡的ViewPager還註冊了OnPageChangeListener介面,每當ViewPager的頁數發現改變時,onPageSelected()方法就會呼叫。我們在這裡讓TextView顯示當前圖片的頁數以及總頁數即可。
目前的ImageDetailsActivity已經具備了翻頁瀏覽圖片的功能了,如果你心急的話,可以現在就執行試一試。不過一但你執行之後,就會發現,我們還有一些細節工作還沒完成。比如說在onCreate()方法中會從Intent中取出要顯示的那張圖片的位置,而很明顯目前是取不到了。於是,我們還需要修改MyScrollView中的程式碼,在這裡將點選的那張圖片的位置傳遞過來。由於這個類中的程式碼非常多,我只列出需要修改的那些部分,如下所示:
public class MyScrollView extends ScrollView implements OnTouchListener {
......
/**
* 開始載入下一頁的圖片,每張圖片都會開啟一個非同步執行緒去下載。
*/
public void loadMoreImages() {
if (hasSDCard()) {
int startIndex = page * PAGE_SIZE;
int endIndex = page * PAGE_SIZE + PAGE_SIZE;
if (startIndex < Images.imageUrls.length) {
Toast.makeText(getContext(), "正在載入...", Toast.LENGTH_SHORT).show();
if (endIndex > Images.imageUrls.length) {
endIndex = Images.imageUrls.length;
}
for (int i = startIndex; i < endIndex; i++) {
LoadImageTask task = new LoadImageTask();
taskCollection.add(task);
task.execute(i);
}
page++;
} else {
Toast.makeText(getContext(), "已沒有更多圖片", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getContext(), "未發現SD卡", Toast.LENGTH_SHORT).show();
}
}
/**
* 遍歷imageViewList中的每張圖片,對圖片的可見性進行檢查,如果圖片已經離開螢幕可見範圍,則將圖片替換成一張空圖。
*/
public void checkVisibility() {
for (int i = 0; i < imageViewList.size(); i++) {
ImageView imageView = imageViewList.get(i);
int borderTop = (Integer) imageView.getTag(R.string.border_top);
int borderBottom = (Integer) imageView.getTag(R.string.border_bottom);
if (borderBottom > getScrollY() && borderTop < getScrollY() + scrollViewHeight) {
String imageUrl = (String) imageView.getTag(R.string.image_url);
Bitmap bitmap = imageLoader.getBitmapFromMemoryCache(imageUrl);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
LoadImageTask task = new LoadImageTask(imageView);
task.execute(i);
}
} else {
imageView.setImageResource(R.drawable.empty_photo);
}
}
}
......
/**
* 非同步下載圖片的任務。
*
* @author guolin
*/
class LoadImageTask extends AsyncTask<Integer, Void, Bitmap> {
/**
* 記錄每個圖片對應的位置
*/
private int mItemPosition;
......
@Override
protected Bitmap doInBackground(Integer... params) {
mItemPosition = params[0];
mImageUrl = Images.imageUrls[mItemPosition];
Bitmap imageBitmap = imageLoader.getBitmapFromMemoryCache(mImageUrl);
if (imageBitmap == null) {
imageBitmap = loadImage(mImageUrl);
}
return imageBitmap;
}
......
/**
* 向ImageView中新增一張圖片
*
* @param bitmap
* 待新增的圖片
* @param imageWidth
* 圖片的寬度
* @param imageHeight
* 圖片的高度
*/
private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth,
imageHeight);
if (mImageView != null) {
mImageView.setImageBitmap(bitmap);
} else {
ImageView imageView = new ImageView(getContext());
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setPadding(5, 5, 5, 5);
imageView.setTag(R.string.image_url, mImageUrl);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), ImageDetailsActivity.class);
intent.putExtra("image_position", mItemPosition);
getContext().startActivity(intent);
}
});
findColumnToAdd(imageView, imageHeight).addView(imageView);
imageViewList.add(imageView);
}
}
......
}
}
可以看到,這裡我們將LoadImageTask 的泛型進行了修改,doInBackground不再接收一個字串陣列,而是接收一個整型陣列,這裡傳入的引數也就代表著每張圖片的位置。這樣的話,每個呼叫LoadImageTask 的地方也都需要進行相應的修改,在loadMoreImages()和checkVisibility()方法中,都將傳入的引數改成了圖片的位置。最後在addImage()方法中,使用Intent將點選的那張圖片對應的位置傳遞給了ImageDetailsActivity。
目前看上去一切都完美了吧!但其實還有一點工作我們還沒完成。由於ViewPager的事件和ZoomImageView的事件是存在衝突的,所以加入了ViewPager後,ZoomImageView本身的單個手指拖動圖片的功能會受很大的影響。所以我們還需要在ZoomImageView的onTouchEvent()中進行判斷,如果當前的圖片是沒有縮放的,則允許通過滑動來切換圖片,如果當前的圖片已經放大了,則要遮蔽掉ViewPager的事件,這樣ZoomImageView本身的事件就不會受影響。程式碼如下所示:
public class ZoomImageView extends View {
......
@Override
public boolean onTouchEvent(MotionEvent event) {
if (initRatio == totalRatio) {
getParent().requestDisallowInterceptTouchEvent(false);
} else {
getParent().requestDisallowInterceptTouchEvent(true);
}
......
return true;
}
......
}
這裡使用getParent()獲取到的就是ViewPager物件,然後呼叫requestDisallowInterceptTouchEvent()方法來啟動和禁用ViewPager的功能。
好了,這樣的話,所有的程式碼就已經完成了,可以執行一下看看完整的效果了。點選任意一張圖片可以檢視大圖,然後通過左右滑動可以瀏覽前後的圖片,並且仍然能夠通過多點觸控對圖片進行縮放,效果如下圖所示:
除了滑動切換圖片之外,在螢幕的底部還能顯示當前圖片的頁數以及總頁數,功能已經是相當完善了。目前這個照片牆Demo的效果已經不亞於市場上一些常見的圖片瀏覽程式了吧。
好了,今天的講解到此結束,有疑問的朋友請在下面留言。
相關文章
- viewpager實現畫廊(一屏多個Fragment)效果ViewpagerFragment
- 使用 RecyclerView 實現 Gallery 畫廊效果,並控制 Item 停留位置View
- Android中使用RecyclerView + SnapHelper實現類似ViewPager效果AndroidViewpager
- CSS3實現3d效果照片牆CSSS33D
- jquery.gridrotator實現響應式圖片展示畫廊效果jQuery
- 使用ViewPager和TabLayout來實現滑動切換效果ViewpagerTabLayout
- PS新手教程-如何使用PS給照片加日光效果
- ViewPager、Fragment和TabLayout實現切頁效果ViewpagerFragmentTabLayout
- 實現畫布的效果
- Android瀑布流照片牆實現,體驗不規則排列的美感Android
- 處理好item點選事件的gallery(畫廊)效果(無bug)事件
- Flutter PIP(畫中畫)效果的實現Flutter
- 一行程式碼實現ViewPager卡片效果行程Viewpager
- Android實現雙層ViewPager巢狀AndroidViewpager巢狀
- Java程式碼實現七夕魔方照片牆Java
- Android UI控制元件系列:Gallery(畫廊檢視)AndroidUI控制元件
- Android使用(TabLayout+ViewPager+fragment)與(FragmentTabHost+ViewPager+Fragment)實現底部狀態列切換AndroidTabLayoutViewpagerFragment
- ios10錶盤畫廊怎麼用 蘋果ios10錶盤畫廊使用教程介紹iOS蘋果
- Android ViewPager使用詳解AndroidViewpager
- 用html5實現圖片的旋轉--照片牆HTML
- dr5.0加強版漢化版 附安裝使用教程
- 簡單題 加強版
- Android ViewPager 的使用總結AndroidViewpager
- 實現給一個DIV加陰影效果!
- android短影片開發,兩個ViewPager聯動效果AndroidViewpager
- Android水波紋效果實現Android
- Android ViewPager 指示器控制元件的最佳實現AndroidViewpager控制元件
- Photopile JS – 幫助你實現精緻的照片堆疊效果JS
- Wondershare Filmora影片疊加教程-輕鬆製作畫中畫效果
- Android實現蛛網背景效果Android
- Android 毛玻璃效果的實現Android
- 短視訊系統,Android 使用MotionLayout實現動畫效果Android動畫
- Android之ViewPager+GridView實現GridView介面滑動AndroidViewpager
- Android開發之ViewPager+Fragment+FragmentTabHost實現底部選單AndroidViewpagerFragment
- Android 弧形ViewPager 和弧形HeaderView(升級版)AndroidViewpagerHeader
- 使用 CSS 實現透明效果CSS
- js實現的密碼強度提示效果JS密碼
- Android開發之ViewPager簡單使用AndroidViewpager