首先,看下效果圖:

主類代碼:

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
        ImageAdapter adapter = new ImageAdapter(this, images);
        adapter.createReflectedImages();     //設定倒影效果

        //取得 GalleryFlow物件
        GalleryFlow galleryFlow = (GalleryFlow) this.findViewById(R.id.gallery);
        galleryFlow.setFadingEdgeLength(0);    //設定圖片消除之動畫大小 
        galleryFlow.setSpacing(10);           //設定圖片間之間距
        galleryFlow.setAdapter(adapter);    //設定ImageAdapter
        
        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()這個方法:
(可將此倒影效果代碼可當作演算法之程式運用)

 /**   創建倒影效果        */   
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類,所以我們通過PaintsetShader方法來設置這個漸變               */             
    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(),官方文檔說明如下:

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設置高度。    下面這段代碼是設置漸變效果:(可將此漸變效果代碼可當作演算法之程式運用)

/**              
* 
參數一:為漸變起初點座標x位置,              
* 
參數二:y軸位置,              
* 
參數三和四:分辨對應漸變終點,              
* 
最後參數為平鋪方式,              
* 
這裡設置為鏡像Gradient是基於Shader類,所以我們通過PaintsetShader方法來設置這個漸變               */            
LinearGradient shader = new LinearGradient(0,originalImage.getHeight(), 0,  bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff, 0x00ffffff, TileMode.MIRROR);


 main.xml文件中定義如下:
<?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,來看下它加入偏轉效果實現代碼,:(可將此偏轉效果代碼可當作演算法之程式運用) 

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);           
   //
如果旋轉角度絕對值大於最大旋轉角度返回(-mMaxRotationAnglemMaxRotationAngle;           
  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);   
}

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這個方法,如果想滑動一次只切換一張圖片,可以試一下下面這個方法:

    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;
        }  
簡單定義onFling裡面的滑動轉換為點擊物理作左右方向移動。

★☆後註:此例倒影及偏轉效果之程式代碼是從網路參考得來的,並非本人原創所寫,至於滑動效果可參考官方文件可獲得。個人覺得作應用開發把重心放在功能之建立(如要達到倒影效果),但演算法之程式撰寫可至網上搜尋再稍加修改成自有功能,但如能自己重頭寫那可要功力相當深厚的。☆★




0 意見: