Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現3D旋轉的View

Android實現3D旋轉的View

編輯:關於Android編程

今天在網上看到一篇文章寫關於Android實現3D旋轉(http://www.ibm.com/developerworks/cn/opensource/os-cn-android-anmt2/index.html?ca=drs-),出於好奇就寫了一個,運行效果如下:

/

下面我們就開始一步步完成這個效果吧。

實現水平滑動

package com.example.rotation3dview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug.HierarchyTraceType;
import android.view.ViewGroup;
import android.widget.ImageView;

public class Rote3DView extends ViewGroup{

	public Rote3DView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initScreens();
	}
	
	public void initScreens(){
		ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); 	
	   	 for (int i = 0; i < 3; i++) { 
			 this.addView(new ImageView(this.getContext()), i, p); 
		 } 
		 ((ImageView)this.getChildAt(0)).setImageResource(R.drawable.page1); 
		 ((ImageView)this.getChildAt(1)).setImageResource(R.drawable.page2); 
		 ((ImageView)this.getChildAt(2)).setImageResource(R.drawable.page3); 
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int childLeft = 0;
		final int childCount = getChildCount();
		for(int i = 0; i< childCount; i++){
			final View childView = getChildAt(i);
			if(childView.getVisibility() != View.GONE){
				final int childWidth = childView.getMeasuredWidth();
				childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight());
				childLeft += childWidth;
			}
		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		final int width = MeasureSpec.getSize(widthMeasureSpec);
		final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		if(widthMode != MeasureSpec.EXACTLY){
			throw new IllegalStateException(僅支持精確尺寸);
		}
		final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		if(heightMode != MeasureSpec.EXACTLY){
			throw new IllegalStateException(僅支持精確尺寸);
		}
		final int count = getChildCount();
		for(int i = 0; i < count; i++){
			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
		}
	}
	
	private float mDownX;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mDownX = x;
			break;
		case MotionEvent.ACTION_MOVE:
			int disX = (int)(mDownX - x);
			mDownX = x;
			scrollBy(disX, 0);
			break;
		case MotionEvent.ACTION_UP:
			
			break;

		default:
			break;
		}
		
		return true;
	}

}
/上面的滑動還不太流暢,我們在手勢抬起的時候進行判斷並處理,代碼如下:
package com.example.rotation3dview;

import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewDebug.HierarchyTraceType;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Scroller;

public class Rote3DView extends ViewGroup{
	private int mCurScreen = 1;
	// 滑動的速度
	private static final int SNAP_VELOCITY = 500;
	private VelocityTracker mVelocityTracker;
	private int mWidth;
	private Scroller mScroller;
	private Camera mCamera;
	private Matrix mMatrix;
	// 旋轉的角度,可以進行修改來觀察效果
	private float angle = 90;
	public Rote3DView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mScroller = new Scroller(context);
		mCamera = new Camera();
		mMatrix = new Matrix();
		initScreens();
	}
	
	public void initScreens(){
		ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); 	
	   	 for (int i = 0; i < 3; i++) { 
			 this.addView(new ImageView(this.getContext()), i, p); 
		 } 
		 ((ImageView)this.getChildAt(0)).setImageResource(R.drawable.page1); 
		 ((ImageView)this.getChildAt(1)).setImageResource(R.drawable.page2); 
		 ((ImageView)this.getChildAt(2)).setImageResource(R.drawable.page3); 
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int childLeft = 0;
		final int childCount = getChildCount();
		for(int i = 0; i< childCount; i++){
			final View childView = getChildAt(i);
			if(childView.getVisibility() != View.GONE){
				final int childWidth = childView.getMeasuredWidth();
				childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight());
				childLeft += childWidth;
			}
		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		final int width = MeasureSpec.getSize(widthMeasureSpec);
		final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		if(widthMode != MeasureSpec.EXACTLY){
			throw new IllegalStateException(僅支持精確尺寸);
		}
		final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		if(heightMode != MeasureSpec.EXACTLY){
			throw new IllegalStateException(僅支持精確尺寸);
		}
		final int count = getChildCount();
		for(int i = 0; i < count; i++){
			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
		}
		scrollTo(mCurScreen * width, 0);
	}
	
	private float mDownX;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(mVelocityTracker == null){
			mVelocityTracker = VelocityTracker.obtain();
		}
		//將當前的觸摸事件傳遞給VelocityTracker對象
		mVelocityTracker.addMovement(event);
		float x = event.getX();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			if(!mScroller.isFinished()){
				mScroller.abortAnimation();
			}
			mDownX = x;
			break;
		case MotionEvent.ACTION_MOVE:
			int disX = (int)(mDownX - x);
			mDownX = x;
			scrollBy(disX, 0);
			break;
		case MotionEvent.ACTION_UP:
			final VelocityTracker velocityTracker = mVelocityTracker;
			velocityTracker.computeCurrentVelocity(1000);
			int velocityX = (int) velocityTracker.getXVelocity();
			if(velocityX > SNAP_VELOCITY && mCurScreen > 0){
				snapToScreen(mCurScreen - 1);
			}else if(velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1){
				snapToScreen(mCurScreen + 1);
			}else{
				snapToDestination();
			}
			if(mVelocityTracker != null){
				mVelocityTracker.recycle();
				mVelocityTracker = null;
			}
			break;
		}
		return true;
	}
	
	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		}
	}
	
	public void snapToDestination(){
		setMWidth();
		final int destScreen = (getScrollX() + mWidth / 2) / mWidth;
		snapToScreen(destScreen);
	}
	
	public void snapToScreen(int whichScreen){
		whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
		setMWidth();
		int scrollX = getScrollX();
		int startWidth = whichScreen * mWidth;
		if(scrollX != startWidth){
			int delta = 0;
			int startX = 0;
			if(whichScreen > mCurScreen){
				setPre();
				delta = startWidth - scrollX;
				startX = mWidth - startWidth + scrollX;
			}else if(whichScreen < mCurScreen){
				setNext();
				delta = -scrollX;
				startX = scrollX + mWidth;
			}else{
				startX = scrollX;
				delta = startWidth - scrollX;
			}
			mScroller.startScroll(startX, 0, delta, 0, Math.abs(delta) * 2);
			invalidate();
		}
	}
	
	private void setNext(){
		int count = this.getChildCount();
		View view = getChildAt(count - 1);
		removeViewAt(count - 1);
		addView(view, 0);
	}
	
	private void setPre(){
		int count = this.getChildCount();
		View view = getChildAt(0);
		removeViewAt(0);
		addView(view, count - 1);
	}
	
	private void setMWidth(){
		if(mWidth == 0){
			mWidth = getWidth();
		}
	}
}

實現立體效果

添加如下代碼:
	/*
	 * 當進行View滑動時,會導致當前的View無效,該函數的作用是對View進行重新繪制 調用drawScreen函數
	 */
	@Override
	protected void dispatchDraw(Canvas canvas) {
		final long drawingTime = getDrawingTime();
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			drawScreen(canvas, i, drawingTime);
		}
	}

	public void drawScreen(Canvas canvas, int screen, long drawingTime) {
		// 得到當前子View的寬度
		final int width = getWidth();
		final int scrollWidth = screen * width;
		final int scrollX = this.getScrollX();
		// 偏移量不足的時
		if (scrollWidth > scrollX + width || scrollWidth + width < scrollX) {
			return;
		}
		final View child = getChildAt(screen);
		final int faceIndex = screen;
		final float currentDegree = getScrollX() * (angle / getMeasuredWidth());
		final float faceDegree = currentDegree - faceIndex * angle;
		if (faceDegree > 90 || faceDegree < -90) {
			return;
		}
		final float centerX = (scrollWidth < scrollX) ? scrollWidth + width
				: scrollWidth;
		final float centerY = getHeight() / 2;
		final Camera camera = mCamera;
		final Matrix matrix = mMatrix;
		canvas.save();
		camera.save();
		camera.rotateY(-faceDegree);
		camera.getMatrix(matrix);
		camera.restore();
		matrix.preTranslate(-centerX, -centerY);
		matrix.postTranslate(centerX, centerY);
		canvas.concat(matrix);
		drawChild(canvas, child, drawingTime);
		canvas.restore();
	}
 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved