Android開發系列(七) Gallery 3D效果


  昨天沒有做更新,原因是一直在看有關Gallery的內容,因為想做一個比較美觀的圖片瀏覽器,如果使用系統自帶的Gallery類效果非常差,因此根據網上的總結,對Gallery類進行繼承,進而對其中的效果進行自定義,可以實現比較美觀的(偽)3D效果。下一節會把ImageSwitcher添加進來,進一步對圖片瀏覽器優化。另外對網上牛人的帖子一並表示感謝。

 

首先是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@android:color/background_dark" >
    
    <com.example.android_myowngallery.MyGallery 
        android:id="@+id/myGallery"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

注意這里因為對View控件進行了繼承,所以控件的類型應該寫成自己定義的那個類類名,否則還會出現ClassCastException

  然后是自己創建的MyGallery類

package com.example.android_myowngallery;

import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;

public class MyGallery extends Gallery{


    /**
     * 注意Gallery類有三個構造函數,在繼承時必須要把這三個構造函數都繼承過來,否則會有異常
     * @param context
     * @param attrs
     * @param defStyle
     */
    public MyGallery(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
    }
    
    public MyGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }
    
    public MyGallery(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    
    /**
     * 覆寫 getChildStaticTransformation方法,正是通過這個方法對Gallery的效果進行修改
     */
    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        // TODO Auto-generated method stub
        //對轉換信息初始化
        t.clear();
    
        //setTransformationType();
        //獲得子控件(ImageView)偏移父控件偏移量 (用比例表示,在-1到1之間)
        float offSet=getOffSet(child);
        //根據偏移量,子控件,轉換信息 進行效果設置
        tranformIamgeView(child, t, offSet); //不要忘記調用圖像變換方法
        
        return true;
    }
    
    
    /**
     * 求出子控件偏移父控件中心的程度
     */
    //求出子控件的中心
    protected int getCenterOfChild(View view){
        
        return view.getLeft()+view.getWidth()/2;
        
        //這里的getLeft()是求出子控件左邊界的橫坐標,在加上一半寬度就是中心的橫坐標了
        
    }
    
    protected int getCenterOfParent()
    {
        //有效寬度=寬度-左右邊框
        //中心橫坐標=左邊框+有效寬度的一半
        return getPaddingLeft()+(getWidth()-getPaddingLeft()-getPaddingRight())/2;
    }
    
    protected float getOffSet(View view)
    {
        float cCenter=getCenterOfChild(view);
        float pCenter=getCenterOfParent();
        float offSet=(cCenter-pCenter)/pCenter;
        if(offSet<-1){
            offSet=-1;
        }
        else if(offSet>1){
            offSet=1;
        }
        return offSet;
    }
    
    
    /**
     * 該方法根據給定的參數進行修改圖像的顯示屬性,實際上就是根據子控件偏移父控件中心的偏移量決定不同的顯示
     * 效果,從而使圖片的切換更加好看
     */
    protected void tranformIamgeView(View view, Transformation t, float offSet)
    {
        //這里創建一個Camera對象通過Camera類的translate方法改變“相機”的角度,進而使圖片呈現不同的效果
        /**
         * android.graphics.Camera
         * 
         * @Camera.save();
         * @Camera.restore();  相機類的這兩個方法需要同時出現
         */
        Camera mCamera=new Camera();
        /**
         * 通過Transformation對象獲得一個Matrix對象,這個對象的方法用於對於圖像坐標變換的屬性進行設置
         * android.graphics.Matrix
         */
        Matrix matrix=t.getMatrix();
        mCamera.save();
        /**
         * z坐標為正時表示“相機”上升,意味着圖像將變小,本例中打算將偏離父控件中心的View縮小,、
         * 所以z應該是正值
         */
        mCamera.translate(0, 0, Math.abs(offSet)*200);
        
        /****
         * ERROR!!
         * 
         * 
         * 將圖片對象添加至矩陣中,這個方法必須再preTranslate的前面,否則對於變換中心的設置是無效的!!
         */
        mCamera.getMatrix(matrix);
        
        //先寬后高,關於這個方法的意義下文討論
        
        matrix.preTranslate(-view.getMeasuredWidth()/2, -view.getMeasuredHeight()/2);
        matrix.postTranslate(view.getMeasuredWidth()/2, view.getMeasuredHeight()/2);
        
    
        
        mCamera.restore();  //將相機的狀態保存
        
        //設置一下透明度Alpha,要注意這里的透明度是子控件ImageView的,如果透明度為0(不透明)
        //那么圖片將不會顯示,如果透明度為1,圖片正常顯示
        t.setAlpha(1-Math.abs(offSet));  

    }
    

}

 

這里matrix.preTranslate(-view.getWidth()/2, -view.getHeight()/2); 

是指在矩陣變換之前把View向左上移動,也就是把矩陣變換的中心點由childView的原點(圖片左上角)變成childView的中心點
      matrix.postTranslate(view.getWidth()/2, view.getWidth()/2);
指在矩陣變換完之后,再把childView向右下方進行平移,移動到原來的位置(即屏幕的中心位置)

另外注意  mCamera.getMatrix()方法應該放在preTranslate()方法前面!

 

  如同ListView一樣,也要為Gallery設置適配器

package com.example.android_myowngallery;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;

public class MyAdapter extends BaseAdapter{

    private Context context;
    private int[] picRes;
    
    
    
    public MyAdapter(Context context, int[] picRes) {
        super();
        this.context = context;
        this.picRes = picRes;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return picRes.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        /**
         * 說明:因為這里只有一個控件ImageView,所以為了簡化代碼在這里直接創建ImageView對象,
         * 在處理每一個GalleryItem中有多個控件時,還是要和ListView一樣自定義每個Item的布局文件,
         * 一般自定義布局時才會使用LayoutInflater的inflate方法創建convertView,然后再進一步獲得子控件的
         * ID,這里不用convertView,因為沒有定義item的布局文件!
         */
        ImageView i=new ImageView(context);
             //遺留問題:這里換成Gallery是否可以?感覺MyGallery還是最好!
        i.setLayoutParams(new MyGallery.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));       //這里必須要創建新對象!並且要使用父控件Gallery的內部類
        i.setImageResource(picRes[position]);
        return i;
    }

}

這里注意本適配器中不需要利用convertView ,只有當有子布局文件時才會通過inflate方法創建此view

最后是MainActivity

package com.example.android_myowngallery;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Gallery;

public class MainActivity extends Activity {

    
    protected int[] picRes={R.drawable.ew23,R.drawable.girl0,R.drawable.girl1,R.drawable.girl2,R.drawable.image01,
            R.drawable.image02,R.drawable.qwe2,R.drawable.w21};
    
    MyGallery g=null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        g=(MyGallery)findViewById(R.id.myGallery);
        MyAdapter adapter=new MyAdapter(this,picRes);
        g.setAdapter(adapter);
    
    }

    

}

這里要創建 MyGallery對象

最后附上一張結果圖吧

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM