/**  * 在网上看到好多的3D画廊的效果,最常见就是Gallery,但是在API16的时候就已经废弃了,现在推荐使用ViewPager和HorizontalScrollView来实现这种效果,下面就在这里对其进行整理一下

Gallery实现

android 画廊居左或居右 android 画廊效果_android

步骤:

1、为Gallery设置Adapter

@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView iv;
            if (convertView != null) {
                iv = (ImageView) convertView;
            } else {
                iv = new ImageView(MainActivity.this);
            }
            //通过调用BitmapUtils的getBitmap方法来得到生成倒影效果的图片
            Bitmap bitmap = BitmapUtils.getImageBitmap(getResources(), res[position]);
            BitmapDrawable bd = new BitmapDrawable(bitmap);
            bd.setAntiAlias(true);//为Bitmap设置抗锯齿效果
            iv.setImageDrawable(bd);
            Gallery.LayoutParams params = new Gallery.LayoutParams(160, 400);
            iv.setLayoutParams(params);//为ImageView设置宽高
            return iv;
        }


2、设置图片倒影效果

public static Bitmap getBitmap(Resources res, int drawableId) {
        Bitmap src_bitmap = BitmapFactory.decodeResource(res, drawableId);//原图
        //1、生成倒影图片
        Matrix matrix = new Matrix();
        matrix.setScale(1, -1);// 让图形按照矩阵进行垂直反转
        Bitmap inverted_Bitmap = Bitmap.createBitmap(src_bitmap, 0, (int) (src_bitmap.getHeight() * 0.5), src_bitmap.getWidth(), src_bitmap.getHeight() / 2, matrix, true);
        //2、得到合成的图片
        Bitmap result = Bitmap.createBitmap(src_bitmap.getWidth(), (int) (src_bitmap.getHeight() * 1.5 + 10), Bitmap.Config.ARGB_8888);
            //将原图和倒影图画到合成图上
        Canvas canvas = new Canvas(result);
        canvas.drawBitmap(src_bitmap, 0, 0, null);
        canvas.drawBitmap(inverted_Bitmap, 0, src_bitmap.getHeight() + 10, null);
        //3、设置遮罩效果
        Paint paint = new Paint();
            // 设置颜色
        LinearGradient lg = new LinearGradient(0, (int) (src_bitmap.getHeight() + 10), 0, result.getHeight(), 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
        paint.setShader(lg);
            // 设置模式为: 遮罩, 是取交集
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.drawRect(0, (int) (src_bitmap.getHeight() + 5), src_bitmap.getWidth(), result.getHeight(), paint);
        src_bitmap.recycle();
        inverted_Bitmap.recycle();
        return result;
    }

       3、自定义Gallery

为了实现3D的效果需要覆盖protected boolean getChildStaticTransformation(View child, Transformation t)方法,通过为transformation设置动画来实现图片3D的浏览效果。

t.clear();// 设置变换效果之前, 需要把Transformation中的上一个item的变换效果清楚
        t.setTransformationType(Transformation.TYPE_MATRIX);// 设置变换效果的类型为矩阵类型

接下来通过使用camera来为图片设置放大、透明度、旋转的效果


private void startTransformation(ImageView child, int rotateAngle, Transformation t) {
        camera.save();// 保存状态
        int absRotateAngle = Math.abs(rotateAngle);	// 取旋转角度的绝对值
        //1、放大效果(中间的图片要比两边的图片要大)
        camera.translate(0, 0, 100);
        int zoom = -250 + absRotateAngle*2 ;
        camera.translate(0, 0, zoom);

        //2、 透明度(中间的图片是完全显示, 两边有一定的透明度)
        int alpha = 255 - 3 * absRotateAngle;
        child.setAlpha(alpha);// 透明度取值范围: 0 ~ 255, 0 就是完全隐藏, 255 完全显示

        //3、旋转(在中间的图片没有旋转角度, 只要不在中间就有旋转角度)
        camera.rotateY(rotateAngle);
        Matrix matrix = t.getMatrix();
        // 给matrix赋值
        camera.getMatrix(matrix);// 把matrix矩阵给camera对象, camera对象就会把上面添加的效果转换成矩阵添加到matrix对象中

凡是大量用到Bitmap的地方都有可能发生OOM异常,为了解决OOM异常这里应用软引用来对图片进行缓存处理

强引用:
    String s = "abc";
    list.add(s);
   
软引用:
    如果若引用对象回收完之后,内存还是报警,继续回收软引用对象,还是继续内存报警,
    OOM outOfMemoryException内存溢出异常
	SoftReference<Bitmap> softReference = new SoftReference<Bitmap>(bitmap);

弱引用:
    如果虚引用对象回收完之后,内存还是报警,继续回收弱引用对象

虚引用:
    虚拟机的内存不够使用,开始报警,这时候垃圾回收机制开始执行System.gc();
    String a = "a";(定义了之后没有用这个对象则回收它)
    如果没有对象回收了,回收虚引用的对象

当然你如果不想自己去写这么多代码,github提供了3DGallery的库

https://github.com/davidschreiber/FancyCoverFlow


使用步骤:

          1、布局文件引用

<at.technikum.mti.fancycoverflow.FancyCoverFlow
        android:id="@+id/fancy_converflow"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
    </at.technikum.mti.fancycoverflow.FancyCoverFlow>

        

  2、对自定义控件进行设置

/**
         * 当然你也可以在xml进行设置
         *fcf:maxRotation="45"
         *fcf:unselectedAlpha="0.3"
         *fcf:unselectedSaturation="0.0"
         *fcf:unselectedScale="0.4"
         *fcf:scaleDownGravity="0.5"
         */
        fancy_converflow.setUnselectedAlpha(1.0f);//未选择的Item透明度
        fancy_converflow.setUnselectedSaturation(0.0f);//未选中的饱和度
        fancy_converflow.setUnselectedScale(0.5f);//未选中的缩放
        fancy_converflow.setSpacing(20);//设置Item之间间隙
        fancy_converflow.setMaxRotation(45);//设置最大的旋转角
        fancy_converflow.setScaleDownGravity(0.5f);//从哪个位置进行缩放
        fancy_converflow.setReflectionEnabled(true);
        fancy_converflow.setReflectionRatio(0.3f);//倒影的比例
        fancy_converflow.setReflectionGap(10);//倒影和原图的间距
        fancy_converflow.setActionDistance(FancyCoverFlow.ACTION_DISTANCE_AUTO);


android 画廊居左或居右 android 画廊效果_ide_02

ViewPager实现

滑动ViewPager页面显示动画效果,你需要去实现ViewPager.PageTransform类,重写public void transformPage(View page, float position) {方法

在Android官方文档提供了两种:ZoomOutPageTransformer、DepthPageTransformer

1、ZoomOutPageTransformer

android 画廊居左或居右 android 画廊效果_ide_03

代码

public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();
 
        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left. 
            view.setAlpha(0);
 
        } else if (position <= 1) { // [-1,1]
            // Modify the default slide transition to shrink the page as well 
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            if (position < 0) {
                view.setTranslationX(horzMargin - vertMargin / 2);
            } else { 
                view.setTranslationX(-horzMargin + vertMargin / 2);
            } 
 
            // Scale the page down (between MIN_SCALE and 1) 
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
 
            // Fade the page relative to its size. 
            view.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                    (1 - MIN_SCALE) * (1 - MIN_ALPHA));
 
        } else { // (1,+Infinity] 
            // This page is way off-screen to the right. 
            view.setAlpha(0);
        } 
    }

2、DepthPageTransformer

代码

android 画廊居左或居右 android 画廊效果_Math_04

public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
 
        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left. 
            view.setAlpha(0);
 
        } else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page 
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);
 
        } else if (position <= 1) { // (0,1]
            // Fade the page out. 
            view.setAlpha(1 - position);
 
            // Counteract the default slide transition 
            view.setTranslationX(pageWidth * -position);
 
            // Scale the page down (between MIN_SCALE and 1) 
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
 
        } else { // (1,+Infinity] 
            // This page is way off-screen to the right. 
            view.setAlpha(0);
        } 
    }


效果

android 画廊居左或居右 android 画廊效果_ide_05

在一个屏幕显示多个Page

//页面宽度所占ViewPager的宽度的比例,默认为1
        @Override
        public float getPageWidth(int position) {
            return 0.4f;
        }

为每个Page添加间距

vp.setPageMargin(30);

代码如下:

public class CustomTransform implements ViewPager.PageTransformer {
    private static final float MIN_SCALE=0.65f;
    private int MAX_ROTATION = 40;
    @Override
    public void transformPage(View page, float position) {
        float scaleFactor=Math.max(MIN_SCALE,1-Math.abs(position));
        float rotate=20*Math.abs(position);
        if (position<-1){
            // This page is way off-screen to the left.
        }else if (position <= 1){
            // Modify the default slide transition to shrink the page as well
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
            page.setRotationY(rotate);
        }else if (position>1) {
            // This page is way off-screen to the right.
        }
    }
}