Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ViewPager 實現 Galler 效果, 中間大圖顯示,兩邊小圖展示

ViewPager 實現 Galler 效果, 中間大圖顯示,兩邊小圖展示

編輯:關於Android編程

正常情況下, ViewPager 一頁只能顯示一項數據, 但是我們常常看到網上,特別是電視機頂盒的首頁經常出現中間大圖顯示兩端也都露出一點來,這種效果怎麼實現呢?先上一張效果圖: \   大家第一眼肯定想到了Gallery,這是最早android圖庫自帶的效果,現在基本不用,那有沒有其他好的辦法呢?我們首先考慮的還是ViewPager+PagerAdapter的實現策略。 後面在網上了搜了一下, 發現要實現上面的效果,我們需要注意兩個方面,首先是怎麼在兩邊顯示兩個小圖,第二,怎麼實現無限滑動。 1,首先就是用到了View的android:clipChildren屬性,.簡單來說父View是默認是束縛子View 的顯示范圍的,所以當我們在父View有 padding , 那麼 子View 則在 padding區域是不能顯示內容的。當設置android:clipChildren="false"的時候,子View 就可以在父View 的padding內容區域顯示內容了。 2,實現無限循環很簡單,網上也有很多的解決方案,我這裡不考慮性能上的東西,且看下面簡單的代碼:
private class ImageAdapter extends PagerAdapter{  
           
        private ArrayList viewlist;  
   
        public ImageAdapter(ArrayList viewlist) {  
            this.viewlist = viewlist;  
        }  
   
        @Override  
        public int getCount() {  
            //設置成最大,使用戶看不到邊界,大家可以去查詢下這個大小  
            return Integer.MAX_VALUE;  
        }       
         @Override    
         public void destroyItem(ViewGroup container, int position,    
                 Object object) {    
             //注:不要在這裡調用removeView  
         }   
		 
         @Override    
         public Object instantiateItem(ViewGroup container, int position) {  
             //對ViewPager頁號求模取出View列表中要顯示的項  
             position %= viewlist.size();  
             if (position<0){  
                 position = viewlist.size()+position;  
             }  
			 
			 //這裡是view
            ViewHolder viewHolder = null;
            View view = LayoutInflater.from(mContext).inflate(
                R.layout.item_finefare_layout, null);
          if (viewHolder == null) {
            viewHolder = new ViewHolder(view);
           }
            bindView(viewHolder, data);

          container.addView(view, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);
             return view;    
         }    
    }  

上面代碼應該注意的幾點:

  • getCount()方法的返回值:這個值直接關系到ViewPager的“邊界”,因此當我們把它設置為Integer.MAX_VALUE之後,用戶基本就看不到這個邊界了(估計滑到這裡的時候電池已經掛了吧o_O)。當然,通常情況下設置為100倍實際內容個數也是可以的,之前看的某個實現就是這麼干的。

  • instantiateItem()方法position的處理:由於我們設置了count為Integer.MAX_VALUE,因此這個position的取值范圍很大很大,但我們實際要顯示的內容肯定沒這麼多(往往只有幾項),所以這裡肯定會有求模操作。但是,簡單的求模會出現問題:考慮用戶向左滑的情形,則position可能會出現負值。所以我們需要對負值再處理一次,使其落在正確的區間內。

  • instantiateItem()方法父組件的處理:通常我們會直接addView,但這裡如果直接這樣寫,則會拋出IllegalStateException。假設一共有三個view,則當用戶滑到第四個的時候就會觸發這個異常,原因是我們試圖把一個有父組件的View添加到另一個組件。

    經過上面的解釋,我們已經很清楚了,以下是代碼的詳細實現,數據來源於網上,大家可以自行模擬:
ViewPager類:
public class WelfareAdapter extends PagerAdapter {

    private Context mContext;
    private List dataList = new ArrayList<>();

    public WelfareAdapter(Context mContext) {
        this.mContext = mContext;
    }

    public void setDatas(List list) {
        if (list.size() <= 0) {
            dataList.clear();
            notifyDataSetChanged();
            return;
        }
        dataList.clear();
        dataList.addAll(list);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        position %= dataList.size();
        if (position<0){
            position = dataList.size()+position;
        }

        PanicBean data = dataList.get(position);

        ViewHolder viewHolder = null;
        View view = LayoutInflater.from(mContext).inflate(
                R.layout.item_finefare_layout, null);
        if (viewHolder == null) {
            viewHolder = new ViewHolder(view);
        }
        bindView(viewHolder, data);

        container.addView(view, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);
        return view;
    }

    private void bindView(ViewHolder viewholder, final PanicBean data) {
        Glide.with(mContext).load(data.pic).into(viewholder.welfareImage);

        viewholder.welfareImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ToastUtils.showToast("你點擊了"+data.href);
            }
        });
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
//        container.removeView((View) object);
    }

    class ViewHolder {
        @BindView(R.id.welfare_image)
        RoundedImageView welfareImage;

        ViewHolder(View view) {
            ButterKnife.bind(this, view);
            view.setTag(this);
        }

        public void reset() {
            welfareImage.setBackground(mContext.getResources().getDrawable(R.drawable.welfare_default_icon));
        }
    }

}
用到的布局:



    


用到的數據Bean(這個大家根據情況自行模擬,只要是個列表就行)
public class FineFareEntity {

    public List panic;

    public static class PanicBean {
        public String id;
        public long endtime;
        public String pic;
        public int type;
        public String href;
        public String title;
        public String share;
    }
}
  為了方便使用我們都自定義成View,方便以後代碼維護:
public class WelfareView extends SimpleLinearLayout {

    @BindView(R.id.finefare_count)
    TextView finefareCount;
    @BindView(R.id.viewPager)
    ViewPager viewPager;
    @BindView(R.id.finefare_name)
    TextView finefareName;
    @BindView(R.id.welfare_view)
    LinearLayout welfareView;

    private WelfareAdapter adapter = null;
    private List welfareList = null;

    public WelfareView(Context context) {
        super(context);
    }

    public WelfareView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void initViews() {
        contentView = inflate(mContext, R.layout.layout_welfare, this);
        ButterKnife.bind(this);

        initViewPager();

        initTouch();

    }

    private void initTouch() {
        //這裡要把父類的touch事件傳給子類,不然邊上的會滑不動
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return viewPager.dispatchTouchEvent(event);
            }
        });

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                position %= welfareList.size();
                if (position<0){
                    position = welfareList.size()+position;
                }
                finefareName.setText(welfareList.get(position).id);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

    }

    private void initViewPager() {
        viewPager.setOffscreenPageLimit(3);
        viewPager.setPageTransformer(true, new ScalePagerTransformer());
        //設置Pager之間的間距
        viewPager.setPageMargin(UIUtils.dp2px(mContext, 15));

        adapter = new WelfareAdapter(mContext);
        viewPager.setAdapter(adapter);
    }

    public void setWelfareData(List datas) {
        this.welfareList = datas;
        welfareView.setVisibility(datas.size()>0?VISIBLE:GONE);
        finefareCount.setText("共有" + datas.size() + "個福利");
        finefareName.setText(welfareList.get(getCurrentDisplayItem()).title);

        adapter = new WelfareAdapter(mContext);
        adapter.setDatas(datas);
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(adapter.getCount() > 0 ? 1 : 0, true);

    }

    public int getCurrentDisplayItem() {
        if (viewPager != null) {
            return viewPager.getCurrentItem();
        }
        return 0;
    }

}
這裡有一個滑動縮放的類:
public class ScalePagerTransformer implements ViewPager.PageTransformer {

        private static final float MIN_SCALE = 0.85f;
        private static final float MIN_ALPHA = 0.5f;

        @Override
        public void transformPage(View view, float position) {
            if (position >= -1 || position <= 1) {
                final float height = view.getHeight();
                final float width = view.getWidth();
                final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
                final float vertMargin = height * (1 - scaleFactor) / 2;
                final float horzMargin = width * (1 - scaleFactor) / 2;

                view.setPivotY(0.5f * height);
                view.setPivotX(0.5f * width);

                if (position < 0) {
                    view.setTranslationX(horzMargin - vertMargin / 2);
                } else {
                    view.setTranslationX(-horzMargin + vertMargin / 2);
                }

                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);

                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
            }
        }
    }

SimpleLinearLayout 類

public class SimpleLinearLayout extends LinearLayout {

    protected Context mContext;
    protected View contentView;
    protected AtomicBoolean isPreparingData;

    public SimpleLinearLayout(Context context) {
        super(context);
        this.mContext = context;
        isPreparingData = new AtomicBoolean(false);
        initViews();
    }

    public SimpleLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        isPreparingData = new AtomicBoolean(false);
        initViews();
    }

    protected void initViews() {

    }

}



用到的布局(android:clipChildren="false"需要注意):

android:clipChildren="false"
    android:layout_marginTop="10dp"
    android:background="@color/c12"
    android:orientation="vertical">


    

        

        

            

            
        
    

    

    


最後就是在我們的主代碼中寫個歌測試了,
 private void initWelfare() {
        String welfare = FileUtils.readAssert(getActivity(), "welfare.txt");
        FineFareEntity entity=JsonUtils.parseJson(welfare,FineFareEntity.class);
        if (entity!=null){
            welfareView.setWelfareData(entity.panic);
        }
    }
涉及到的布局:

這裡的FileUtils.readAssert 代碼:
public static String readAssert(Context context, String fileName){
        String resultString="";
        try {
            InputStream inputStream=context.getResources().getAssets().open(fileName);
            byte[] buffer=new byte[inputStream.available()];
            inputStream.read(buffer);
            resultString=new String(buffer,"utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }
最後為了方便大家的模擬,我把數據給大家,有點多,大家自己放到assert目錄下,
{
panic: [
{
id: "2412",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M04/E3/67/CgvUBVe9vyOAV47CAACXZZs5GrU558_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n770",
title: "今日限時搶",
share: ""
},
{
id: "2417",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M09/E4/37/CgvUA1e91VmAMYrwAAC5qcblOUg650_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n781",
title: "今日限時搶",
share: ""
},
{
id: "2413",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M05/E3/D4/CgvUA1e9v2SAVf3qAAB9GcBIWYA268_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n771",
title: "今日限時搶",
share: ""
},
{
id: "2414",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M05/E3/69/CgvUBVe9v4aAMaFRAABWy73vn2g252_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n772",
title: "今日限時搶",
share: ""
},
{
id: "2415",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M06/E3/02/CgvUBFe9v6WAP85NAAC6EK5e5Vg469_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n773",
title: "今日限時搶",
share: ""
},
{
id: "2416",
endtime: 1472097600000,
pic: "http://pc1.img.ymatou.com/G02/M06/E3/02/CgvUBFe9v8CAHyXVAACELcKFT_M328_o.jpg",
type: 1,
href: "http://evt.ymatou.com/n775",
title: "今日限時搶",
share: ""
}
]
}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved