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(); final Matrix imageMatrix = t.getMatrix(); //圖片高度 final int
imageHeight = child.getLayoutParams().height; //圖片寬度 final int
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(); } |
先看下主類代碼:
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 extends Activity { /** Called when the activity is first created. */ @Override public void
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 = new ImageAdapter( this , images);
adapter.createReflectedImages(); //創建倒影效果
GalleryFlow galleryFlow = (GalleryFlow) this .findViewById(R.id.gallery);
galleryFlow.setFadingEdgeLength( 0 );
galleryFlow.setSpacing( 10 ); //圖片之間的間距
galleryFlow.setAdapter(adapter);
galleryFlow.setOnItemClickListener( new OnItemClickListener() {
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 */ public boolean
createReflectedImages() { //倒影圖和原圖之間的距離 final int
reflectionGap = 4 ; int index =
0 ; for ( int
imageId : mImageIds) {
//返回原圖解碼之後的bitmap對象
Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId);
int width = originalImage.getWidth();
int height = originalImage.getHeight();
//創建矩陣對象
Matrix matrix = new Matrix();
//指定一個角度以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 = new Canvas(bitmapWithReflection);
canvas.drawBitmap(originalImage, 0 , 0 ,
null );
Paint deafaultPaint = new Paint();
deafaultPaint.setAntiAlias( false );
// canvas.drawRect(0, height, width, height + reflectionGap,deafaultPaint);
canvas.drawBitmap(reflectionImage, 0 , height + reflectionGap, null );
Paint paint = new Paint();
paint.setAntiAlias( false );
/**
* 參數一:爲漸變起初點座標x位置,
* 參數二:爲y軸位置,
* 參數三和四:分辨對應漸變終點,
* 最後參數爲平鋪方式,
* 這裏設置爲鏡像Gradient是基於Shader類,所以我們通過Paint的setShader方法來設置這個漸變
*/
LinearGradient shader = new LinearGradient( 0 ,originalImage.getHeight(), 0 , bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff , 0x00ffffff ,
TileMode.MIRROR);
//設置陰影
paint.setShader(shader);
paint.setXfermode( new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
//用已經定義好的畫筆構建一個矩形陰影漸變效果
canvas.drawRect( 0 , height, width, bitmapWithReflection.getHeight()+ reflectionGap, paint);
//創建一個ImageView用來顯示已經畫好的bitmapWithReflection
ImageView imageView = new ImageView(mContext);
imageView.setImageBitmap(bitmapWithReflection);
//設置imageView大小 ,也就是最終顯示的圖片大小
imageView.setLayoutParams( new GalleryFlow.LayoutParams( 200 , 300 ));
//imageView.setScaleType(ScaleType.MATRIX);
mImages[index++] = imageView; } return true ; } |
先獲取倒影,然後把倒影和原照片合成一張圖片。裏面使用到了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, int y,
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 if the 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 = new LinearGradient( 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 extends Gallery{ private Camera mCamera =
new Camera(); //相機類 private int
mMaxRotationAngle = 60 ; //最大轉動角度 private int
mMaxZoom = - 280 ; ////最大縮放值 private int
mCoveflowCenter; //半徑值 public GalleryFlow(Context context) { super (context); //支持轉換 ,執行getChildStaticTransformation方法 this .setStaticTransformationsEnabled( true ); } public GalleryFlow(Context context, AttributeSet attrs) {
super (context, attrs);
this .setStaticTransformationsEnabled( true ); } public GalleryFlow(Context context, AttributeSet attrs,
int defStyle) {
super (context, attrs, defStyle);
this .setStaticTransformationsEnabled( true ); } /** * 獲取旋轉最大角度 * @return */ public int
getMaxRotationAngle() {
return mMaxRotationAngle; } /** * 設置旋轉最大角度 * @param maxRotationAngle */ public void
setMaxRotationAngle( int maxRotationAngle) {
mMaxRotationAngle = maxRotationAngle; } /** * 獲取最大縮放值 * @return */ public int
getMaxZoom() {
return mMaxZoom; } /** * 設置最大縮放值 * @param maxZoom */ public void
setMaxZoom( int maxZoom) {
mMaxZoom = maxZoom; } /** * 獲取半徑值 * @return */ private int
getCenterOfCoverflow() {
return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft(); } /** * @param view * @return */ private static
int getCenterOfView(View view) {
return view.getLeft() + view.getWidth() / 2 ; } //控制gallery中每個圖片的旋轉(重寫的gallery中方法) protected boolean
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 ; } /** * */ protected void
onSizeChanged( int w,
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中方法) protected boolean
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 ; } |
先根據圖片所處的位置計算出需要旋轉的角度,然後進行旋轉:
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(); final Matrix imageMatrix = t.getMatrix(); //圖片高度 final int
imageHeight = child.getLayoutParams().height; //圖片寬度 final int
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
|
private boolean
isScrollingLeft(MotionEvent e1, MotionEvent e2) {
return e2.getX() > e1.getX(); } @Override public boolean
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 ;
} |