[應用代碼] 自定義帶倒影和偏轉的超炫Gallery

代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void transformImageBitmap(ImageView child, Transformation t,
                   int rotationAngle) {
        //對效果進行保存
        mCamera.save();
        finalMatrix imageMatrix = t.getMatrix();
        //圖片高度
        finalint imageHeight = child.getLayoutParams().height;
        //圖片寬度
        finalint imageWidth = child.getLayoutParams().width;
       
        //返回旋轉角度的絕對值
        final int rotation = Math.abs(rotationAngle);
       
        // 在Z軸上正向移動camera的視角,實際效果爲放大圖片。
        // 如果在Y軸上移動,則圖片上下移動;X軸上對應圖片左右移動。
        mCamera.translate(0.0f,0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation *1.5));
            mCamera.translate(0.0f,0.0f, zoomAmount);
        }
        // 在Y軸上旋轉,對應圖片豎向向裏翻轉。
        // 如果在X軸上旋轉,則對應圖片橫向向裏翻轉。
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight /2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight /2));
        mCamera.restore();
    }
效果圖:
1334024172_9023.jpg
3 天前 上傳
下載附件(18.11 KB)


先看下主類代碼:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class GalleryDemoActivity extendsActivity {
    /** Called when the activity is first created. */
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);    
        setContentView(R.layout.main);
       
        Integer[] images = { R.drawable.image01,
                                                R.drawable.image02,
                                                R.drawable.image03,
                                                R.drawable.image04,
                                                R.drawable.image05};
       
        ImageAdapter adapter = newImageAdapter(this, images);
        adapter.createReflectedImages();//創建倒影效果
        GalleryFlow galleryFlow = (GalleryFlow) this.findViewById(R.id.gallery);
        galleryFlow.setFadingEdgeLength(0);
        galleryFlow.setSpacing(10);//圖片之間的間距
        galleryFlow.setAdapter(adapter);
       
        galleryFlow.setOnItemClickListener(newOnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                   int position, long id) {
               Toast.makeText(getApplicationContext(), String.valueOf(position), Toast.LENGTH_SHORT).show();
            }
           
        });
        galleryFlow.setSelection(4);
    }



比較簡單,先來看下倒影效果是如何實現的,在ImageAdapter類裏找到createReflectedImages()這個方法:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
     * 創建倒影效果
     * @return
     */
    publicboolean createReflectedImages() {
     //倒影圖和原圖之間的距離
     finalint reflectionGap = 4;
     intindex = 0;
     for(int imageId : mImageIds) {
              //返回原圖解碼之後的bitmap對象
              Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId);
              int width = originalImage.getWidth();
              int height = originalImage.getHeight();
              //創建矩陣對象
              Matrix matrix = newMatrix();
             
              //指定一個角度以0,0爲座標進行旋轉
              // matrix.setRotate(30);
             
              //指定矩陣(x軸不變,y軸相反)
              matrix.preScale(1, -1);
             
              //將矩陣應用到該原圖之中,返回一個寬度不變,高度爲原圖1/2的倒影位圖
              Bitmap reflectionImage = Bitmap.createBitmap(originalImage,0,
               height/2, width, height/2, matrix,false);
             
              //創建一個寬度不變,高度爲原圖+倒影圖高度的位圖
              Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
               (height + height / 2), Config.ARGB_8888);
             
              //將上面創建的位圖初始化到畫布
              Canvas canvas = newCanvas(bitmapWithReflection);
              canvas.drawBitmap(originalImage, 0,0, null);
             
              Paint deafaultPaint = newPaint();
              deafaultPaint.setAntiAlias(false);
        //    canvas.drawRect(0, height, width, height + reflectionGap,deafaultPaint);
              canvas.drawBitmap(reflectionImage, 0, height + reflectionGap,null);
              Paint paint = newPaint();
              paint.setAntiAlias(false);
              
              /**
               * 參數一:爲漸變起初點座標x位置,
               * 參數二:爲y軸位置,
               * 參數三和四:分辨對應漸變終點,
               * 最後參數爲平鋪方式,
               * 這裏設置爲鏡像Gradient是基於Shader類,所以我們通過Paint的setShader方法來設置這個漸變
               */
              LinearGradient shader = newLinearGradient(0,originalImage.getHeight(),0,
                     bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff,0x00ffffff, TileMode.MIRROR);
              //設置陰影
              paint.setShader(shader);
              paint.setXfermode(newPorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
              //用已經定義好的畫筆構建一個矩形陰影漸變效果
              canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()+ reflectionGap, paint);
             
              //創建一個ImageView用來顯示已經畫好的bitmapWithReflection
              ImageView imageView = newImageView(mContext);
              imageView.setImageBitmap(bitmapWithReflection);
              //設置imageView大小 ,也就是最終顯示的圖片大小
              imageView.setLayoutParams(newGalleryFlow.LayoutParams(200,300));
              //imageView.setScaleType(ScaleType.MATRIX);
              mImages[index++] = imageView;
     }
     returntrue;
    }



先獲取倒影,然後把倒影和原照片合成一張圖片。裏面使用到了bitmap的靜態方法createBitmap(),看下官方文檔:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public static Bitmap createBitmap (Bitmap source, int x, inty, int width, int height, Matrix m,boolean filter)
Since: API Level 1
Returns an immutable bitmap from subset of the source bitmap, transformed by the optional matrix. It is initialized with the same density as the original bitmap.
Parameters
source        The bitmap we are subsetting
x        The x coordinate of the first pixel in source
y        The y coordinate of the first pixel in source
width        The number of pixels in each row
height        The number of rows
m        Optional matrix to be applied to the pixels
filter        true if the source should be filtered. Only applies ifthe matrix contains more than just translation.
Returns
A bitmap that represents the specified subset of source
Throws
IllegalArgumentException       if the x, y, width, height values are outside of the dimensions of the source bitmap.



參數x、y就是開始複製的起點座標,就是從原圖的那個座標點開始複製,width設置複製的寬度,height設置高度。

因爲代碼中註釋較詳細,這裏不再多說。

下面這段代碼是設置漸變效果:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
/**
               * 參數一:爲漸變起初點座標x位置,
               * 參數二:爲y軸位置,
               * 參數三和四:分辨對應漸變終點,
               * 最後參數爲平鋪方式,
               * 這裏設置爲鏡像Gradient是基於Shader類,所以我們通過Paint的setShader方法來設置這個漸變
               */
              LinearGradient shader = newLinearGradient(0,originalImage.getHeight(),0,
                     bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff,0x00ffffff, TileMode.MIRROR);


看完倒影,再來看一下偏轉,在main.xml文件中:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <nsouth.jonas.android.GalleryFlow
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:id="@+id/gallery"
         />
</LinearLayout>


只有一個自定義的GalleryFlow,來看下它的代碼:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
public class GalleryFlow extendsGallery{
        privateCamera mCamera = newCamera();//相機類
    privateint mMaxRotationAngle =60;//最大轉動角度
    privateint mMaxZoom = -280;////最大縮放值
    privateint mCoveflowCenter;//半徑值
    publicGalleryFlow(Context context) {
        super(context);
        //支持轉換 ,執行getChildStaticTransformation方法
        this.setStaticTransformationsEnabled(true);
    }
   
    publicGalleryFlow(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setStaticTransformationsEnabled(true);
    }
   
    publicGalleryFlow(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setStaticTransformationsEnabled(true);
    }
   
    /**
     * 獲取旋轉最大角度
     * @return
     */
    publicint getMaxRotationAngle() {
        return mMaxRotationAngle;
    }
   
    /**
     * 設置旋轉最大角度
     * @param maxRotationAngle
     */
    publicvoid setMaxRotationAngle(intmaxRotationAngle) {
        mMaxRotationAngle = maxRotationAngle;
    }
   
    /**
     * 獲取最大縮放值
     * @return
     */
    publicint getMaxZoom() {
        return mMaxZoom;
    }
   
    /**
     * 設置最大縮放值
     * @param maxZoom
     */
    publicvoid setMaxZoom(intmaxZoom) {
        mMaxZoom = maxZoom;
    }
   
    /**
     * 獲取半徑值
     * @return
     */
    privateint getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) /2
                       + getPaddingLeft();
    }
   
    /**
     * @param view
     * @return
     */
    privatestatic int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() /2;
    }  
   
   //控制gallery中每個圖片的旋轉(重寫的gallery中方法)
    protectedboolean getChildStaticTransformation(View child, Transformation t) { 
        //取得當前子view的半徑值
        final int childCenter = getCenterOfView(child);      
        final int childWidth = child.getWidth();
        //旋轉角度
        int rotationAngle = 0;
        //重置轉換狀態
        t.clear();
        //設置轉換類型
        t.setTransformationType(Transformation.TYPE_MATRIX);
        //如果圖片位於中心位置不需要進行旋轉
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {
            //根據圖片在gallery中的位置來計算圖片的旋轉角度
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            System.out.println("rotationAngle:"+rotationAngle);
            //如果旋轉角度絕對值大於最大旋轉角度返回(-mMaxRotationAngle或mMaxRotationAngle;)
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
               rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);
        }
        return true;
    }
   
    /**
     *
     */
    protectedvoid onSizeChanged(intw, int h, int oldw, int oldh) {
        mCoveflowCenter = getCenterOfCoverflow();
        super.onSizeChanged(w, h, oldw, oldh);
    }
   
}


主要的方法就是:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//控制gallery中每個圖片的旋轉(重寫的gallery中方法)
    protectedboolean getChildStaticTransformation(View child, Transformation t) { 
        //取得當前子view的半徑值
        finalint childCenter = getCenterOfView(child);      
        finalint childWidth = child.getWidth();
        //旋轉角度
        introtationAngle = 0;
        //重置轉換狀態
        t.clear();
        //設置轉換類型
        t.setTransformationType(Transformation.TYPE_MATRIX);
        //如果圖片位於中心位置不需要進行旋轉
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {
            //根據圖片在gallery中的位置來計算圖片的旋轉角度
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            System.out.println("rotationAngle:"+rotationAngle);
            //如果旋轉角度絕對值大於最大旋轉角度返回(-mMaxRotationAngle或mMaxRotationAngle;)
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
               rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);
        }
        return true;
    }


先根據圖片所處的位置計算出需要旋轉的角度,然後進行旋轉:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
   //根據圖片在gallery中的位置來計算圖片的旋轉角度
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            System.out.println("rotationAngle:"+rotationAngle);
            //如果旋轉角度絕對值大於最大旋轉角度返回(-mMaxRotationAngle或mMaxRotationAngle;)
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);


主要功能實現是在transformImageBitmap()這個方法:
代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void transformImageBitmap(ImageView child, Transformation t,
                   int rotationAngle) {
        //對效果進行保存
        mCamera.save();
        finalMatrix imageMatrix = t.getMatrix();
        //圖片高度
        finalint imageHeight = child.getLayoutParams().height;
        //圖片寬度
        finalint imageWidth = child.getLayoutParams().width;
       
        //返回旋轉角度的絕對值
        final int rotation = Math.abs(rotationAngle);
       
        // 在Z軸上正向移動camera的視角,實際效果爲放大圖片。
        // 如果在Y軸上移動,則圖片上下移動;X軸上對應圖片左右移動。
        mCamera.translate(0.0f,0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation *1.5));
            mCamera.translate(0.0f,0.0f, zoomAmount);
        }
        // 在Y軸上旋轉,對應圖片豎向向裏翻轉。
        // 如果在X軸上旋轉,則對應圖片橫向向裏翻轉。
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight /2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight /2));
        mCamera.restore();
    }


主要進行翻轉操作。

關於滑動速度的修改需要重寫onFling這個方法,如果想滑動一次只切換一張圖片,可以試一下下面這個方法:

代碼片段,雙擊複製
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
    privateboolean isScrollingLeft(MotionEvent e1, MotionEvent e2) { 
            return e2.getX() > e1.getX(); 
       
     
        @Override 
        publicboolean onFling(MotionEvent e1, MotionEvent e2,float velocityX,float velocityY) { 
            // e1是按下的事件,e2是擡起的事件 
            int keyCode; 
            if (isScrollingLeft(e1, e2)) { 
                keyCode = KeyEvent.KEYCODE_DPAD_LEFT; 
            } else
               keyCode = KeyEvent.KEYCODE_DPAD_RIGHT; 
           
            onKeyDown(keyCode, null); 
            return true
       

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章