1. 程式人生 > >Android自定義元件系列【11】——實現3D立體旋轉效果

Android自定義元件系列【11】——實現3D立體旋轉效果

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();
		}
	}
}

實現立體效果

新增如下程式碼:

相關推薦

Android定義元件系列11——實現3D立體旋轉效果

package com.example.rotation3dview; import android.content.Context; import android.graphics.Camera; import android.graphics.Canvas; import android.graphic

Android定義元件系列2——Scroller類

在上一篇中介紹了View類的scrollTo和scrollBy兩個方法,對這兩個方法不太瞭解的朋友可以先看《自定義View及ViewGroup》scrollTo和scrollBy雖然實現了檢視的偏移,但是卻沒有更好的控制移動過程,移動是瞬間進行的。Scroller類就是為解決

百度分享怎麽 定義圖片分享 原創

多功能 有道 amp popu har dia 1.0 例如 IV 我們在應用百度分享插件的時候, 默認如果開啟圖片分享的話,連很多小圖標也分享了,實在惱火! 去掉圖片分享吧,分享效果又不好。。。 如何做到自定義圖片分享呢? 就是預先定義tag標簽 例如: "tag":

Android 定義View 系列文章目錄 Canvas篇

一、基礎 Android 畫筆 Paint  基本操作API:https://blog.csdn.net/huangliniqng/article/details/82588824 Android 畫布 Canvas 基本操作API:https://blog.csdn.net/

Android定義View系列:標籤LabelView實戰篇

前言部分 本文主要介紹如何自定義一個常見的labels標籤,功能上主要支援,單選、多選、點選三種模式。因為這個使用率很高,並且這個是比較典型學習自定義ViewGroup的例子,所以特意動手實踐,加深對Android的認識。這個專案主要是為了自己學習使用,所以並不是很完善,先上一個效果

Android定義元件(四)

1.陰影 陰影即可以為文字和圖形指定陰影,預設情況下,我們的文字和圖形都是繪製在主層(main layer)上,我們也可以將內容繪製到新的layer上,實際上陰影就是在main layer的下面添加了一個陰影層。 Paint類為此定義了一個名為setShadowLayer

循序漸進學.Net Core Web Api開發系列11:依賴注入

系列目錄 一、概述 本篇介紹如何採用依賴注入的方式建立和使用物件,主要從應用層面進行描述,不涉及具體的內部原理。 二、演練 假設要做一個日誌服務的類,它實現在控制檯打印出帶時間資訊的日誌資訊。 首先定義該服務的介面與實現類。 public interface ILogSe

QtQt之定義搜尋框

簡述 關於搜尋框,大家都經常接觸。例如:瀏覽器搜尋、Windows資源管理器搜尋等。 當然,這些對於Qt實現來說毫無壓力,只要思路清晰,分分鐘搞定。 簡述 效果 細節分析 原始碼下載 效果 細節分析 實現細節需要如下步驟: 組合實現,輸入框+

Android定義元件之日曆控制元件-精美日曆實現(內容、樣式可擴充套件)

需求 我們知道,Android系統本身有自帶的日曆控制元件,網路上也有很多開源的日曆控制元件資源,但是這些日曆控制元件往往樣式較單一,API較多,不易於在實際專案中擴充套件並實現出符合具體樣式風格的,內容可定製的效果。本文通過自定義日曆控制元件,實現了在內容和樣

Android定義元件之美化radiobutton

其實美化方法很簡單隻需重寫ondraw方法是替換圖片即可 下面是原始碼 package com.myradio; import android.content.Context; import android.graphics.Canvas; import an

Android定義佈局系列之一:流式佈局(含TextView的點選事件)

前言:   之前寫了Unity優化方面的文章,之後就沒寫了。之後想把C盤擴大點,室友試了分割槽助手,很好用,也成功了,我心動也試了下,以為不會出什麼意外,更不會出現資料丟失,抱著僥倖的心理沒臨時備份,哎!沒想到最重要的E盤(所有資料)裡所有資料都丟失了,之後用了資料恢復,

「HTML+CSS」--定義按鈕樣式001

# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的

「HTML+CSS」--定義按鈕樣式002

# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的

「HTML+CSS」--定義按鈕樣式003

# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的

「HTML+CSS」--定義按鈕樣式004

# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的

Android 定義View-----流式佈局(粗糙實現)

//首先檢視一下佈局介面吧 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app

定義view系列(5)--99.99%實現QQ側滑刪除效果

首先宣告本文是基於GitHub上"baoyongzhang"的SwipeMenuListView修改而來, 可以說這個側滑刪除效果是我見過效果最好且比較靈活的專案,沒有之一!!! 但是在使用它之前需要給大家提兩點注意事項: 1,該專案支援Gradle dependence

Android定義View之導航欄(Fragment實現)

安卓輕量級底部導航欄 目前安卓開發中常常會用到底部導航欄這個控制元件,但是自己從零開始做一個又太麻煩。因此,我封裝了一個底部導航欄,同時,也做了一些修改,用於頂部也十分合適。下面是示例圖: 使用方法: 1.新增依賴 首先,在build.gradle檔案下加入 maven

Android定義View——貝塞爾曲線實現水波紋進度球

效果圖 原理分析 首先需要了解的水波紋實現效果,可以在部落格的自定義View專題找到,其實現原理如下 利用貝塞爾曲線繪製螢幕外和螢幕內的sin曲線 利用path將sin曲線的左下角和右下角連線起來成為一塊區域 通過不斷的平移sin曲線,然後平移完

android定義View(2):實現百分比適應佈局

android介面適配難是歷史原因,我們只能想辦法解決。github上面已有一些佈局自適應的解決方案,今天我分享的是自定義控制元件:RelativieLayout自適應百分比寬高。直接上菜。 一,實現的效果圖 眼見為實,截圖所示,寬高都是50%,實現了自