Android利用ViewPager實現可滑動放大縮小畫廊效果_Android

來源:互聯網
上載者:User

畫廊在很多的App設計中都有,如下圖所示:


該例子是我沒事的時候寫的一個小項目,具體源碼地址請訪問https://github.com/AlexSmille/YingMi。

該畫廊類似封面的效果,滑到中間的圖片會慢慢變大,離開的View會慢慢的縮小,同時可設定滑動監聽和點擊監聽。

網上有很多例子都是通過Gallery實現的,而上例的實現是通過ViewPager實現,解決了效能最佳化的問題,今天特此把它抽出來,封裝一下,以便以後的方便使用。最終實現的效果如下:

使用方式

布局中添加該自訂控制項

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 布局中添加自訂控制項--> <com.mahao.alex.customviewdemo.viewpager.CoverFlowViewPager android:id="@+id/cover" android:layout_width="match_parent" android:layout_height="wrap_content" /></RelativeLayout>

代碼中設定

代碼中設定分為以下幾個步驟:
 •尋找控制項
 •初始化資料
 •將需要顯示的資料設定到控制項上
 •設定滑動監聽 

public class MainActivity extends AppCompatActivity { private CoverFlowViewPager mCover; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mCover = (CoverFlowViewPager) findViewById(R.id.cover); // 初始化資料 List<View> list = new ArrayList<>(); for(int i = 0;i<10;i++){  ImageView img = new ImageView(this);  img.setBackgroundColor(Color.parseColor("#"+getRandColorCode()));  list.add(img); } //設定顯示的資料 mCover.setViewList(list); // 設定滑動的監聽,該監聽為當前頁面滑動到中央時的索引 mCover.setOnPageSelectListener(new OnPageSelectListener() {  @Override  public void select(int position) {  Toast.makeText(getApplicationContext(),position+"",Toast.LENGTH_SHORT).show();  } }); } /** * 擷取隨機顏色,便於區分 * @return */ public static String getRandColorCode(){ String r,g,b; Random random = new Random(); r = Integer.toHexString(random.nextInt(256)).toUpperCase(); g = Integer.toHexString(random.nextInt(256)).toUpperCase(); b = Integer.toHexString(random.nextInt(256)).toUpperCase(); r = r.length()==1 ? "0" + r : r ; g = g.length()==1 ? "0" + g : g ; b = b.length()==1 ? "0" + b : b ; return r+g+b; }}

實現原理

實現過程中有兩個痛點:
 •如何?滑動過程中的放大與縮小
 •如何顯示ViewPager中未被顯示的頁面 

如何?滑動過程中的放大與縮小?

在設定每一個ViewPager 的頁面時,對每一個頁面都設定一個固定的padding值,這樣每個頁面都會顯示縮小狀態。同時ViewPager設定addOnPageChangeListener(),滑動監聽,在該滑動監聽中會回調ViewPager的滑動的狀態,滑動的位移量等,根據滑動的位移量進行放大縮小。及根據padding值設定控制項的顯示大小

如何顯示ViewPager中未被顯示的頁面

在xml中有一個不常用的屬性android:clipChildren,是否限制子View的顯示。設定為false,則子View的顯示不受父控制項的限制。

代碼實現

編寫控制項的布局檔案

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clipChildren="false"> <android.support.v4.view.ViewPager android:id="@+id/vp_conver_flow" android:layout_width="180dp" android:layout_height="260dp" android:layout_centerHorizontal="true" android:clipChildren="false" /></RelativeLayout>

 一個相對布局中嵌入一個ViewPager,相對布局用於確定顯示的範圍,ViewPager用以實現滑動,放大縮小等。

建立CoverFlowViewPager,載入布局

/** * * 實現封面瀏覽 * Created by alex_mahao on 2016/8/25. */public class CoverFlowViewPager extends RelativeLayout implements OnPageSelectListener { /** * 用於左右滾動 */ private ViewPager mViewPager; public CoverFlowViewPager(Context context, AttributeSet attrs) { super(context, attrs); inflate(context, R.layout.widget_cover_flow,this); mViewPager = (ViewPager) findViewById(R.id.vp_conver_flow); //init(); }

尋找控制項,並載入布局。

編寫適配器,實現滑動的監聽

既然有了ViewPager,那麼肯定要有適配器Adapter。因為我們要在滑動監聽中,根據位移量操作每一個子項目,放大或縮小,而對於子項目,當然適配器最容易擷取,所以將Adapter實現了ViewPager的滑動監聽介面。

/** * 滾動的適配器 * Created by alex_mahao on 2016/8/25. */public class CoverFlowAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener { /** * 預設縮小的padding值 */ public static int sWidthPadding; public static int sHeightPadding; /** * 子項目的集合 */ private List<View> mViewList; /** * 滑動監聽的回調介面 */ private OnPageSelectListener listener; /** * 內容物件 */ private Context mContext; public CoverFlowAdapter(List<View> mImageViewList, Context context) { this.mViewList = mImageViewList; mContext = context; // 設定padding值 sWidthPadding = dp2px(24); sHeightPadding = dp2px(32); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mViewList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { View view = mViewList.get(position); container.addView(view); return view; } @Override public int getCount() { return mViewList == null ? 0 : mViewList.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // 該方法回調ViewPager 的滑動位移量 if (mViewList.size() > 0 && position < mViewList.size()) {  //當前手指觸摸滑動的頁面,從0頁滑動到1頁 offset越來越大,padding越來越大  Log.i("info", "重新設定padding");  int outHeightPadding = (int) (positionOffset * sHeightPadding);  int outWidthPadding = (int) (positionOffset * sWidthPadding);  // 從0滑動到一時,此時position = 0,其應該是縮小的,符合  mViewList.get(position).setPadding(outWidthPadding, outHeightPadding, outWidthPadding, outHeightPadding);  // position+1 為即將顯示的頁面,越來越大  if (position < mViewList.size() - 1) {  int inWidthPadding = (int) ((1 - positionOffset) * sWidthPadding);  int inHeightPadding = (int) ((1 - positionOffset) * sHeightPadding);  mViewList.get(position + 1).setPadding(inWidthPadding, inHeightPadding, inWidthPadding, inHeightPadding);  } } } @Override public void onPageSelected(int position) { // 回調選擇的介面 if (listener != null) {  listener.select(position); } } @Override public void onPageScrollStateChanged(int state) { } /** * 當將某一個作為最中央時的回調 * * @param listener */ public void setOnPageSelectListener(OnPageSelectListener listener) { this.listener = listener; } /** * dp 轉 px * * @param dp * @return */ public int dp2px(int dp) { int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics()); return px; }}

改代碼分為兩部分,PagerAdapter實現,滑動監聽的實現。PagerAdapter的實現不在多說,最基礎的東西。重點在滑動監聽的實現。

滑動監聽有三個回調方法:其中onPageScrolled(int position, float positionOffset, int positionOffsetPixels)回調的便是ViewPager的滑動得位移量,我們再次動態設定相應元素的padding值,實現放大縮小。

onPageSelected()為選中的回調,通過自訂介面的方式回調給其調用者。後面會提。

初始化ViewPager

既然有了適配器,那麼自然就開始編寫適配器的部分:

 /** * 初始化方法 */ private void init() { // 構造適配器,傳入資料來源 mAdapter = new CoverFlowAdapter(mViewList,getContext()); // 設定選中的回調 mAdapter.setOnPageSelectListener(this); // 設定適配器 mViewPager.setAdapter(mAdapter); // 設定滑動的監聽,因為adpter實現了滑動回調的介面,所以這裡直接設定adpter mViewPager.addOnPageChangeListener(mAdapter); // 自己百度 mViewPager.setOffscreenPageLimit(5); // 設定觸摸事件的分發 setOnTouchListener(new OnTouchListener() {  @Override  public boolean onTouch(View v, MotionEvent event) {  // 傳遞給ViewPager 進行滑動處理  return mViewPager.dispatchTouchEvent(event);  } }); }

注釋很詳細,唯一需要解釋的便是事件的分發。

我們的ViewPager的大小是固定的,只有中間的顯示地區,那麼對於手指在兩個側邊滑動時,ViewPager自然接受不到觸摸事件,通過設定外層相對布局的觸摸事件監聽,將觸摸的事件傳遞到ViewPager,實現滑動ViewPager之外地區時,ViewPager仍能夠實現對應的滑動。

資料來源的封裝

適配器有了,ViewPager也有了,那麼只剩下資料來源了。

因為我們是根據設定padding值實現的,那麼對於需要顯示的控制項,他的背景將無法實現放大縮小,所以對控制項在封裝一層外部控制項,這樣設定外部控制項的padding值,自然需要顯示的控制項會放大縮小。

 /** * 設定顯示的資料,進行一層封裝 * @param lists */ public void setViewList(List<View> lists){ if(lists==null){  return; } mViewList.clear(); for(View view:lists){  FrameLayout layout = new FrameLayout(getContext());  // 設定padding 值,預設縮小  layout.setPadding(CoverFlowAdapter.sWidthPadding,CoverFlowAdapter.sHeightPadding,CoverFlowAdapter.sWidthPadding,CoverFlowAdapter.sHeightPadding);  layout.addView(view);  mViewList.add(layout); } // 重新整理資料 mAdapter.notifyDataSetChanged(); }

選中監聽的回調

當我們滑動時,可能會根據不同的滑動,顯示不同的資料。

通過設定滑動監聽之後,對onPageSelected實現層層的介面回調。

介面的定義OnPageSelectListener

public interface OnPageSelectListener { void select(int position);}

CoverFlowAdapter中添加回調

 @Override public void onPageSelected(int position) { // 回調選擇的介面 if (listener != null) {  listener.select(position); } }

CoverFlowViewPager中添加回調

 // 顯示的回調 @Override public void select(int position) { if(listener!=null){  listener.select(position); } }

點擊事件的設定

直接對資料來源迴圈設定監聽即可

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.