android 3D立体菜单,Android自己定义组件系列【11】——实现3D立体旋转效果

1407400620_5547.gif

以下我们就開始一步步完毕这个效果吧。

实现水平滑动

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;

}

}

1407401735_9815.gif

上面的滑动还不太流畅。我们在手势抬起的时候进行推断并处理,代码例如以下:

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

}

项目完整源码下载:https://code.csdn.net/lxq_xsyu/rotation3dview

Git下载地址:git@code.csdn.net:lxq_xsyu/rotation3dview.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值