ViewPager 实现 GallerView 效果, 显示左右两边 ViewPager Transform 使用详解

来源:互联网 发布:中级js面试题及答案 编辑:程序博客网 时间:2024/05/02 02:22


from:

 http://blog.csdn.net/chen930724/article/details/50464069

http://blog.csdn.net/chen930724/article/details/50466199


项目引用效果图 :



引用:

@AfterViewsvoid initALL() {initDemand();}


private void initDemand() {String uri = Utils.getGetRequestURI("Demand.List","PageSize=" + 10,"CurrentPageIndex=" + 1,"data=null");getDemandData(uri);}



@Backgroundvoid getDemandData(String url, String... params) {String isRet = null;try {isRet = HttpManage.httpGet(context, url, null);isRet = js.reLogin(null, url, "get", null, new JSONObject(isRet));} catch (Exception e) {}reflashDemandData(isRet);}

@UiThreadvoid reflashDemandData(String data) {if (!StringUtil.isEmpty(data)) {JSONArray lists;String list;homeModels = new ArrayList<>();try {list = new JSONObject(data).getString("list");lists = new JSONArray(list);if (lists.length() == 0) {MyToast.show(context, "需求数据为空!", Toast.LENGTH_SHORT);return;}for (int i = 0; i < lists.length(); i++) {HomeDemandModel hdm = new HomeDemandModel();try {hdm.setIcon(new JSONObject(lists.getJSONObject(i).getString("propBuyer")).getString("fdBuyeImage"));hdm.setBuyerName(new JSONObject(lists.getJSONObject(i).getString("propBuyer")).getString("fdBuyeName"));JSONArray imgJSArr = new JSONArray(lists.getJSONObject(i).getString("propImages"));List<String> imgList = new ArrayList<>();for (int imgIndex = 0; imgIndex < imgJSArr.length(); imgIndex++) {imgList.add(imgJSArr.getJSONObject(imgIndex).getString("fdDeimImage"));}hdm.setImgList(imgList);} catch (Exception e) {hdm.setIcon("");hdm.setImgList(new ArrayList<String>());hdm.setBuyerName("");}hdm.setDemandAccount(lists.getJSONObject(i).getString("fdDemaTitle"));hdm.setCreatTime(lists.getJSONObject(i).getString("propCreateAtName"));hdm.setPerData(lists.getJSONObject(i).toString());homeModels.add(hdm);}} catch (Exception e) {MyToast.show(context, "数据加载异常!", Toast.LENGTH_SHORT);return;}DemandSlideAdapter slidDemandAdapter = new DemandSlideAdapter(LayoutInflater.from(this), this);demandPager.setAdapter(slidDemandAdapter);demandPager.setOffscreenPageLimit(3);// 设置跳跃幅度过大 ANR出现 设置为45就好demandPager.setCurrentItem(5);demandPager.setPageTransformer(true, new MyPageTransformer());demandPager.setHorizontalFadingEdgeEnabled(false);int windowWidth = DeviceUtil.getScreenPixels((Activity) context).getWidth();int PaddingLeftOrRight = 10;int MarginRightOrLeft = 4;int viewPagerHeight = (windowWidth - TranslatingUtil.Dp2Px(context, PaddingLeftOrRight) * 2- TranslatingUtil.Dp2Px(context, 50) * 2- TranslatingUtil.Dp2Px(context, MarginRightOrLeft) * 2) / 3  //前边计算图片高度//计算其他高度+ TranslatingUtil.Dp2Px(context, 43 + 38 + 9);//宽度减去左右marginLinearLayout.LayoutParams llViewpager = new LinearLayout.LayoutParams(windowWidth - TranslatingUtil.Dp2Px(context, 50) * 2 ,viewPagerHeight);llViewpager.leftMargin = TranslatingUtil.Dp2Px(context, 50);llViewpager.rightMargin = TranslatingUtil.Dp2Px(context, 50);demandPager.setLayoutParams(llViewpager);//viewpager 获得 父类焦点mViewPagerBox.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                return demandPager.dispatchTouchEvent(event);            }       });slidDemandAdapter.notifyDataSetChanged();}elseMyToast.show(this, "需求数据返回空", Toast.LENGTH_SHORT);}

private static float defaultScale = (float) 14 / (float) 15;public class MyPageTransformer implements ViewPager.PageTransformer {    @SuppressLint("CutPasteId")@Override    public void transformPage(View view, float position) {        View cardView = view.findViewById(R.id.demandPr);        View img = view.findViewById(R.id.demandPr);        int diffWidth = (cardView.getWidth() - img.getWidth()) / 2;        if (position < -1) { // [-Infinity,-1)            cardView.setScaleX(defaultScale);            cardView.setScaleY(defaultScale);            img.setTranslationX(diffWidth);        } else if (position <= 0) { // [-1,0]            cardView.setScaleX((float) 1 + position / (float) 15);            cardView.setScaleY((float) 1 + position / (float) 15);            img.setTranslationX((0 - position) * diffWidth);        } else if (position <= 1) { // (0,1]            cardView.setScaleX((float) 1 - position / (float) 15);            cardView.setScaleY((float) 1 - position / (float) 15);            img.setTranslationX((0 - position) * diffWidth);        } else { // (1,+Infinity]            cardView.setScaleX(defaultScale);            cardView.setScaleY(defaultScale);            img.setTranslationX(-diffWidth);        }    }}class DemandSlideAdapter extends PagerAdapter {private LayoutInflater inflater;public DemandSlideAdapter(LayoutInflater inflater, Context context) {super();this.inflater = inflater;}@Overridepublic int getCount() {return homeModels.size();}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}@SuppressWarnings("deprecation")public Object instantiateItem(ViewGroup container, int position) {View imageLayout = inflater.inflate(R.layout.correcting3_pggmall_home_demand_item, container,false);final HomeDemandModel hdm = homeModels.get(position);imageLayout.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {demandPr(hdm.getPerData());}});CircleImageView demandIcon = (CircleImageView) imageLayout.findViewById(R.id.demandIcon);TextView demandBuyer = (TextView) imageLayout.findViewById(R.id.demandBuyer);;TextView demandTitle = (TextView) imageLayout.findViewById(R.id.demandTitle);;TextView demandTime = (TextView) imageLayout.findViewById(R.id.demandTime);;ImageView demImg1 = (ImageView) imageLayout.findViewById(R.id.demImg1);ImageView demImg2 = (ImageView) imageLayout.findViewById(R.id.demImg2);ImageView demImg3 = (ImageView) imageLayout.findViewById(R.id.demImg3);ImageView [] imgsArr = new ImageView[]{demImg1,demImg2,demImg3};int windowWidth = DeviceUtil.getScreenPixels((Activity) context).getWidth();int PaddingLeftOrRight = 10;int MarginRightOrLeft = 4;int imgWidthOrHeight = (windowWidth - TranslatingUtil.Dp2Px(context, PaddingLeftOrRight) * 2- TranslatingUtil.Dp2Px(context, 50) * 2- TranslatingUtil.Dp2Px(context, MarginRightOrLeft) * 2) / 3;LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(imgWidthOrHeight, imgWidthOrHeight);llp.height = llp.width = llp.width + TranslatingUtil.Dp2Px(context, MarginRightOrLeft);demImg1.setLayoutParams(llp);demImg1.setPadding(0, 0, TranslatingUtil.Dp2Px(context, MarginRightOrLeft), 0);demImg2.setLayoutParams(llp);demImg2.setPadding(0, 0, TranslatingUtil.Dp2Px(context, MarginRightOrLeft), 0);llp.height = llp.width = llp.width - TranslatingUtil.Dp2Px(context, MarginRightOrLeft);demImg3.setLayoutParams(llp);demImg3.setPadding(0, 0, 0, 0);if ( ! StringUtil.isEmpty(hdm.getIcon())) BitmapManage.getInstance(context).get(hdm.getIcon(), demandIcon);demandBuyer.setText(hdm.getBuyerName());demandTitle.setText(hdm.getDemandAccount());demandTime.setText(hdm.getCreatTime());int imgIndex = 0;for (String imgUrl : hdm.getImgList()) {if (imgIndex >= imgsArr.length) break;if ( ! StringUtil.isEmpty(imgUrl)) {BitmapManage.getInstance(context).get(imgUrl, imgsArr[imgIndex]);imgsArr[imgIndex].setVisibility(View.VISIBLE);}else imgsArr[imgIndex].setVisibility(View.INVISIBLE);imgIndex++;}try {if (imageLayout.getParent() == null) {// container.addView(view);//这里可能会报一个错。must call// removeView().on the child....firstcontainer.addView(imageLayout);}} catch (Exception e) {e.printStackTrace();}return imageLayout;}public void destroyItem(ViewGroup container, int position, Object object) {((ViewPager) container).removeView((View) object);}}


// 需求点击跳转void demandPr(String perData) {if (StringUtil.isEmpty(perData))return;startActivity(new Intent(this, C3_DemandDetailActivity_.class).putExtra("per_data", perData));}



引用以上博文正文如下:

正常情况下, ViewPager  一页只能显示一项数据, 
但是如果需求是,  除了小显示本页数据, 还有包 左右两半的数据 也都露出一点来呢?

这该怎么处理?

后面在网上了搜了一下, 发现有不少这样得到文章, 这里自己也写一篇总结一下.

其实 主要就是用到 View 的 android:clipChildren 属性.
简单来说这个属性,  就是 父View 是否 束缚 子View 的显示范围.
如果 父View  有 padding , 那么 子View 则在 padding区域是不能显示内容的, 
但是如果 设置 android:clipChildren 为 false 时, 则子View 就可以在 父View 的padding屈戌显示内容了.

ok 基本了解了 android:clipChildren  那么来处理一下  ViewPager吧

先看一下我做的demo: 


基本就是上面那样, 除了可以显示 当先项的内容, 还可以显示 左右两边的内容.

下面贴一下主要代码:
布局文件: 
[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     android:id="@+id/view_pager_box"  
  4.     xmlns:android="http://schemas.android.com/apk/res/android"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="360dp"  
  7.     android:layout_marginTop="30dp"  
  8.     android:clipChildren="false"  
  9.     >  
  10.   
  11.     <android.support.v4.view.ViewPager  
  12.         android:id="@+id/view_pager"  
  13.         android:layout_width="match_parent"  
  14.         android:layout_height="match_parent"  
  15.         android:layout_marginLeft="50dp"  
  16.         android:layout_marginRight="50dp"  
  17.         android:clipChildren="false"  
  18.   
  19.         />  
  20.   
  21. </RelativeLayout>  

可以在看到 
外层的 RelativeLayout 设置了android:clipChildren 为false
ViewPager 同样页设置了 android:clipChildren 为false
需要两个都设置, 不然会出问题

activity 相关代码 
[java] view plain copy
  1. public class MainActivity extends AppCompatActivity {  
  2.   
  3.     ViewPager mViewPager;  
  4.     RelativeLayout mViewPagerBox;  
  5.   
  6.     private ViewPagerAdapter1 mViewPagerAdapter1;  
  7.   
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.activity_main);  
  12.   
  13.         mViewPager = (ViewPager) findViewById(R.id.view_pager);  
  14.         mViewPagerBox = (RelativeLayout) findViewById(R.id.view_pager_box);  
  15.   
  16.         mViewPager.setOffscreenPageLimit(3);  
  17.   
  18.         mViewPagerAdapter1 = new ViewPagerAdapter1(this);  
  19.         mViewPager.setAdapter(mViewPagerAdapter1);  
  20.   
  21.         mViewPagerBox.setOnTouchListener(new View.OnTouchListener() {  
  22.             @Override  
  23.             public boolean onTouch(View v, MotionEvent event) {  
  24.                 return mViewPager.dispatchTouchEvent(event);  
  25.             }  
  26.         });  
  27.   
  28.     }  
  29. }  


可以看到 和使用普通的 Viewpager 没有任何的区别,
需要注意的是, 为了能够滑动 左右漏出的两边时,  也能滑动 ViewPager 
需要吧 Viewpager 的 父View收到的事件 传递给 viewpager

ok  很简单 就实现了.
但是总感觉,  不是很好看,  
向实现,  左右两半的 与中间 有点距离,
用时 左右两边的 图片, 比中间的图片小一点,  在滑动到中间的时候, 逐渐方法 这个怎么实现呢?

我们在使用Viewpager 的时候, 经常 会加入一些好看的滑动效果这个是怎么实现的呢?
其实很简单,  google 以及为我提供了相应的方法.
通过 setPageTransformer 就可以设置 Viewpager的滑动效果.

Android 官方文档 已经提供了两种 滑动效果:
http://developer.android.com/intl/zh-cn/training/animation/screen-slide.html

ZoomOutPageTransformer: 


[java] view plain copy
  1. public class ZoomOutPageTransformer implements ViewPager.PageTransformer {  
  2.     private static final float MIN_SCALE = 0.85f;  
  3.     private static final float MIN_ALPHA = 0.5f;  
  4.   
  5.     public void transformPage(View view, float position) {  
  6.         int pageWidth = view.getWidth();  
  7.         int pageHeight = view.getHeight();  
  8.   
  9.         if (position < -1) { // [-Infinity,-1)  
  10.             // This page is way off-screen to the left.  
  11.             view.setAlpha(0);  
  12.   
  13.         } else if (position <= 1) { // [-1,1]  
  14.             // Modify the default slide transition to shrink the page as well  
  15.             float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));  
  16.             float vertMargin = pageHeight * (1 - scaleFactor) / 2;  
  17.             float horzMargin = pageWidth * (1 - scaleFactor) / 2;  
  18.             if (position < 0) {  
  19.                 view.setTranslationX(horzMargin - vertMargin / 2);  
  20.             } else {  
  21.                 view.setTranslationX(-horzMargin + vertMargin / 2);  
  22.             }  
  23.   
  24.             // Scale the page down (between MIN_SCALE and 1)  
  25.             view.setScaleX(scaleFactor);  
  26.             view.setScaleY(scaleFactor);  
  27.   
  28.             // Fade the page relative to its size.  
  29.             view.setAlpha(MIN_ALPHA +  
  30.                     (scaleFactor - MIN_SCALE) /  
  31.                     (1 - MIN_SCALE) * (1 - MIN_ALPHA));  
  32.   
  33.         } else { // (1,+Infinity]  
  34.             // This page is way off-screen to the right.  
  35.             view.setAlpha(0);  
  36.         }  
  37.     }  
  38. }  


DepthPageTransformer:

[java] view plain copy
  1. public class DepthPageTransformer implements ViewPager.PageTransformer {  
  2.     private static final float MIN_SCALE = 0.75f;  
  3.   
  4.     public void transformPage(View view, float position) {  
  5.         int pageWidth = view.getWidth();  
  6.   
  7.         if (position < -1) { // [-Infinity,-1)  
  8.             // This page is way off-screen to the left.  
  9.             view.setAlpha(0);  
  10.   
  11.         } else if (position <= 0) { // [-1,0]  
  12.             // Use the default slide transition when moving to the left page  
  13.             view.setAlpha(1);  
  14.             view.setTranslationX(0);  
  15.             view.setScaleX(1);  
  16.             view.setScaleY(1);  
  17.   
  18.         } else if (position <= 1) { // (0,1]  
  19.             // Fade the page out.  
  20.             view.setAlpha(1 - position);  
  21.   
  22.             // Counteract the default slide transition  
  23.             view.setTranslationX(pageWidth * -position);  
  24.   
  25.             // Scale the page down (between MIN_SCALE and 1)  
  26.             float scaleFactor = MIN_SCALE  
  27.                     + (1 - MIN_SCALE) * (1 - Math.abs(position));  
  28.             view.setScaleX(scaleFactor);  
  29.             view.setScaleY(scaleFactor);  
  30.   
  31.         } else { // (1,+Infinity]  
  32.             // This page is way off-screen to the right.  
  33.             view.setAlpha(0);  
  34.         }  
  35.     }  
  36. }  

其实从google 给的两个demo 的注释中可以看出一些端倪.
在 transformPage 方法中, 会传递两个参数,
且 该View  对应 当前的 position

从注释中可以看到,  
position 有一下几个区间:
[-∞ , -1)  :
     表示左边 的View 且已经看不到了
[-1 ,   0]  :
     表示左边的 View ,且可以看见
( 0 ,   1]  :
     表示右边的VIew , 且可以看见了
( 1 , -∞)  :     
     表示右边的 View 且已经看不见了

上面讲的有些模糊,  举个例子

a 是第一页
b 是第二页
当前页为 a, 当  a  向左滑动,  直到滑到 b 时:
a 的position变化是  [-1 ,   0]   由  0  慢慢变到 -1
b 的position变化是  ( 0 ,   1]   由  1  慢慢变到  0

当前页为b,  当 b 向右滑动, 直到滑到a 时:
a 的position变化是  [-1 ,   0]   由  -1  慢慢变到 0
b 的position变化是  ( 0 ,   1]   由   0   慢慢变到 1

了解了这些后, 那么其他的事情 就是在更具position 来写不同的动画了


ok  之前有一篇博客 是写到 关于 Viewpager 来实现 画廊效果, 但是 没有滑动效果.
这里自定义一个  PageTransformer 来实现滑动效果:
先看图 

可以看到 较 之前那篇博客 好看了很多, 下面上代码:

[java] view plain copy
  1. private static float defaultScale = (float14 / (float15;  
  2.   
  3. public class MyPageTransformer implements ViewPager.PageTransformer {  
  4.     @Override  
  5.     public void transformPage(View view, float position) {  
  6.         View cardView = view.findViewById(R.id.img_box);  
  7.         View img = view.findViewById(R.id.img);  
  8.   
  9.         int diffWidth = (cardView.getWidth() - img.getWidth()) / 2;  
  10.   
  11.         if (position < -1) { // [-Infinity,-1)  
  12.             cardView.setScaleX(defaultScale);  
  13.             cardView.setScaleY(defaultScale);  
  14.             img.setTranslationX(diffWidth);  
  15.   
  16.         } else if (position <= 0) { // [-1,0]  
  17.             cardView.setScaleX((float1 + position / (float15);  
  18.             cardView.setScaleY((float1 + position / (float15);  
  19.             img.setTranslationX((0 - position) * diffWidth);  
  20.   
  21.         } else if (position <= 1) { // (0,1]  
  22.             cardView.setScaleX((float1 - position / (float15);  
  23.             cardView.setScaleY((float1 - position / (float15);  
  24.             img.setTranslationX((0 - position) * diffWidth);  
  25.   
  26.         } else { // (1,+Infinity]  
  27.             cardView.setScaleX(defaultScale);  
  28.             cardView.setScaleY(defaultScale);  
  29.             img.setTranslationX(-diffWidth);  
  30.         }  
  31.     }  
  32. }  

其实很简单, 就是更具 position 处理向右的属性动画
当处于 [-Infinity,-1) 时,  是左边的看不见的, 则设在 scaleXY 缩小
当处于 [-Infinity,-1) 时,  是右边的看不见的, 则设在 scaleXY 缩小
当处于 [-Infinity,-1) 时,  是右边的看不见的, 则设在 scaleXY (float) 1 + position / (float) 15 更具 position来变化

需要注意的是,  除了设在 scaleXY  我还设置了 translationX
这是因为, 没 Item里面的土坯那 是wrap_content 且剧中
所以如果是长条状的图,  那么即使设在 android:clipChildren = false  页还是看不到 那张图,
这里 设在 setTranslationX 就是 吧 处于中间的长条状的图, 移到边上来, 
这样即使 左右两面 是 长条状的图, 也能看到了 


0 0