转载请注明出处:(http://blog.csdn.net/qq_35071078/article/details/53158376)
本人学android也有几个月了,最近开始了我的第一个项目,由于项目需要,要实现一个类似于这种的3d菜单,可以滑动。对于一个菜鸟来说,想实现这种效果肯定很难啊,所以就想在网上找源码来学习一下。可是啊,这个东西真的不好找啊,找了几天,在各个android论坛上都发了帖子,基本上没人告诉我准确的解决方法,但是基本上就这三个方向:3d画廊、Rotate3dAnimation、opengl。可以,那就先看下3d画廊吧,看了之后发现网上各种各样的关于3d画廊的帖子,但是根本就不是我想要的效果,我要的是整体的3d效果,可以旋转的。然后又看Rotate3dAnimation,试了很久,发现它只能绕某个坐标轴进行旋转,不知道是不是我没弄懂,毕竟这里面包含了Camera还有Matrix,还要涉及到矩阵的运算,我的天,pass掉。最后又看了两天opengl,好了可以直接pass掉了(具体原因我就不说了,这个东西一两天是学不好的)。很着急啊,过了一个星期了一点进展都没有,最后听了一个网友的话,做一个伪3d算了(其实就是2d),花了半天时间写了这个东西,虽然很预期差的很远,不过看上去还是可以的。下面奉上我的代码(毕竟菜鸟,哈哈,有可能写的很糟,实现了GesturListener基本上没用),另外这只实现了基本上的旋转的效果,对于imageView的Touch事件没有做任何处理。
基本思路: 就是用了属性动画,用一个AnimatorSet来同时播放每个ImageView的动画。
import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; /** * Created by cx on 2016/11/10. */ public class My3dView extends ViewGroup implements GestureDetector.OnGestureListener{ /** * 三个imageView */ ImageView[] items = new ImageView[3]; /** * */ GestureDetector gestureDetector; /** * 动画集合 */ AnimatorSet animatorSet = new AnimatorSet(); AnimatorSet animatorSetBackFirst = new AnimatorSet(); AnimatorSet animatorSetBackSecond = new AnimatorSet(); /** * 判断动画是否正在运行 */ boolean isAnimating = false; /** * 控件的宽和高 */ int mWidth; int mHeight; /** * 自定义的单位宽度。(为了后面方便计算控件的各个位置) */ int unitWidth; /** * 当前item所在的位置 */ int centerItem = 1; int leftItem = 0; int rightItem = 2; public My3dView(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); gestureDetector = new GestureDetector(context, this); } public My3dView(Context context) { super(context,null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 获取当前控件的宽高,并将高分为8小块(分为8小块,主要是为了方便后面对动画参数的计算)。 */ mHeight = MeasureSpec.getSize(heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); unitWidth = mHeight / 8; } @Override protected void onLayout(boolean b, int i, int i1, int i2, int i3) { /** * 获取三个item */ items[0] = (ImageView) getChildAt(0); items[1] = (ImageView) getChildAt(1); items[2] = (ImageView) getChildAt(2); /** * 给三个item指定初始大小 * 左边的item和右边的item都设置alpha为0.5 */ items[0].layout((mWidth/2-unitWidth*8),unitWidth*1,(mWidth/2-unitWidth*4),unitWidth*5); items[0].setAlpha(0.5f); items[1].layout((mWidth-unitWidth*4)/2,unitWidth*4,(mWidth/2+unitWidth*2),mHeight); items[2].layout((mWidth/2+unitWidth*4),unitWidth*1,(mWidth/2+unitWidth*8),unitWidth*5); items[2].setAlpha(0.5f); } @Override public boolean onDown(MotionEvent motionEvent) { Log.e("infoo","onDown"); return true; } @Override public void onShowPress(MotionEvent motionEvent) { Log.e("infoo","onShowPress"); } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { Log.e("infoo","onSingleTapUp"); return false; } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { Log.e("infoo","onScroll motionX = "+motionEvent.getX()+" motion1X=="+motionEvent1.getX()); return false; } @Override public void onLongPress(MotionEvent motionEvent) { Log.e("infoo","onLongPress"); } @Override public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { Log.e("infoo","onFling"); return false; } /* @Override public boolean dispatchTouchEvent(MotionEvent ev) { getParent().requestDisallowInterceptTouchEvent(true); // 先告诉父Viewgroup,不要拦截我我 gestureDetector.onTouchEvent(ev); // 通过GestureDetector将MotionEvent事件交给监听器OnGestureListener return super.dispatchTouchEvent(ev); }*/ @Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN){ /** * 判断当前动画是否正在执行 */ if (!isAnimating){ animatorSet.removeAllListeners(); animatorSetBackFirst = new AnimatorSet(); animatorSetBackSecond = new AnimatorSet(); /** * 计算当前的三个item各在什么位置 */ if(centerItem == 0){ leftItem = 2; rightItem = 1; }else{ leftItem = (centerItem-1)>=0?(centerItem-1):2; rightItem = (centerItem-2)>=0?(centerItem-2):2; } if((event.getX()<mWidth/2)&&!isAnimating){ /** * 控制三个item的动画,包括x轴平移,y轴平移,alpha动画 */ ObjectAnimator ob_center = new ObjectAnimator().ofFloat(items[centerItem],"x",(mWidth-unitWidth*4)/2,(mWidth/2+unitWidth*4)); ObjectAnimator ob_center2 = new ObjectAnimator().ofFloat(items[centerItem],"y",unitWidth*4,unitWidth*1); ObjectAnimator ob_center3 = new ObjectAnimator().ofFloat(items[centerItem],"alpha",1.0f,0.5f); ob_center.setInterpolator(new DecelerateInterpolator()); ObjectAnimator ob_left = new ObjectAnimator().ofFloat(items[leftItem],"x",(mWidth/2-unitWidth*8),(mWidth-unitWidth*4)/2); ObjectAnimator ob_left2 = new ObjectAnimator().ofFloat(items[leftItem],"y",unitWidth*1,unitWidth*4); ObjectAnimator ob_left3 = new ObjectAnimator().ofFloat(items[leftItem],"alpha",0.5f,1.0f); ob_left2.setInterpolator(new DecelerateInterpolator()); ObjectAnimator ob_right = new ObjectAnimator().ofFloat(items[rightItem],"x",(mWidth/2+unitWidth*4),(mWidth-unitWidth*4)/2); ObjectAnimator ob_right2 = new ObjectAnimator().ofFloat(items[rightItem],"y",unitWidth*1,-unitWidth); ObjectAnimator ob_right3 = new ObjectAnimator().ofFloat(items[rightItem],"alpha",0.5f,0.5f); ob_right.setInterpolator(new AccelerateInterpolator()); ObjectAnimator ob_back = new ObjectAnimator().ofFloat(items[rightItem],"x",(mWidth-unitWidth*4)/2,(mWidth/2-unitWidth*8)); ObjectAnimator ob_back2 = new ObjectAnimator().ofFloat(items[rightItem],"y",-unitWidth,unitWidth*1); ObjectAnimator ob_back3 = new ObjectAnimator().ofFloat(items[rightItem],"alpha",0.5f,0.5f); ob_back.setInterpolator(new DecelerateInterpolator()); animatorSetBackSecond.playTogether(ob_back,ob_back2,ob_back3); animatorSetBackSecond.setDuration(500); animatorSetBackFirst.playTogether(ob_right,ob_right2,ob_right3); animatorSetBackFirst.setDuration(500); animatorSetBackFirst.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { animatorSetBackSecond.start(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); animatorSet.playTogether(ob_center,ob_center2,ob_center3,ob_left,ob_left2,ob_left3); /** * 给animatorSet指定Interpolator */ //animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(1000); /** * 给animatorSet添加监听器 */ animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { animatorSetBackFirst.start(); isAnimating = true; } @Override public void onAnimationEnd(Animator animator) { centerItem = ((centerItem-1)>=0?(centerItem-1):2); isAnimating = false; } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); animatorSet.start(); }else if((event.getX()>mWidth/2)&&!isAnimating){ // animatorSet.removeAllListeners(); /** * 控制三个item的动画,包括x轴平移,y轴平移,alpha动画 */ ObjectAnimator ob_center = new ObjectAnimator().ofFloat(items[centerItem],"x",(mWidth-unitWidth*4)/2,(mWidth/2-unitWidth*8)); ObjectAnimator ob_center2 = new ObjectAnimator().ofFloat(items[centerItem],"y",unitWidth*4,unitWidth*1); ObjectAnimator ob_center3 = new ObjectAnimator().ofFloat(items[centerItem],"alpha",1.0f,0.5f); ob_center.setInterpolator(new DecelerateInterpolator()); ObjectAnimator ob_left = new ObjectAnimator().ofFloat(items[leftItem],"x",(mWidth/2-unitWidth*8),(mWidth-unitWidth*4)/2); ObjectAnimator ob_left2 = new ObjectAnimator().ofFloat(items[leftItem],"y",unitWidth*1,-unitWidth); ObjectAnimator ob_left3 = new ObjectAnimator().ofFloat(items[leftItem],"alpha",0.5f,0.5f); ob_left.setInterpolator(new AccelerateInterpolator()); ObjectAnimator ob_right = new ObjectAnimator().ofFloat(items[rightItem],"x",(mWidth/2+unitWidth*4),(mWidth-unitWidth*4)/2); ObjectAnimator ob_right2 = new ObjectAnimator().ofFloat(items[rightItem],"y",unitWidth*1,unitWidth*4); ObjectAnimator ob_right3 = new ObjectAnimator().ofFloat(items[rightItem],"alpha",0.5f,1.0f); ob_right2.setInterpolator(new DecelerateInterpolator()); ObjectAnimator ob_back = new ObjectAnimator().ofFloat(items[leftItem],"x",(mWidth-unitWidth*4)/2,(mWidth/2+unitWidth*4)); ObjectAnimator ob_back2 = new ObjectAnimator().ofFloat(items[leftItem],"y",-unitWidth,unitWidth*1); ObjectAnimator ob_back3 = new ObjectAnimator().ofFloat(items[leftItem],"alpha",0.5f,0.5f); ob_back.setInterpolator(new DecelerateInterpolator()); animatorSetBackSecond.playTogether(ob_back,ob_back2,ob_back3); animatorSetBackSecond.setDuration(500); animatorSetBackFirst.playTogether(ob_left,ob_left2,ob_left3); animatorSetBackFirst.setDuration(500); animatorSetBackFirst.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { animatorSetBackSecond.start(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); animatorSet.playTogether(ob_center,ob_center2,ob_center3,ob_right,ob_right2,ob_right3); animatorSet.setDuration(1000); /** * 给animatorSet指定Interpolator */ // animatorSet.setInterpolator(new DecelerateInterpolator()); /** * 给animatorSet添加监听器 */ animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { isAnimating = true; animatorSetBackFirst.start(); } @Override public void onAnimationEnd(Animator animator) { centerItem = ((centerItem+1)<=2?(centerItem+1):0); isAnimating = false; } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); animatorSet.start(); } } } return gestureDetector.onTouchEvent(event); }
使用的话直接在布局文件中引用这个自定义View,另外在子布局中添加三个imageView:
<com.example.liuzhiyang.test3d.My3dView android:id="@+id/id_3dView" android:layout_width="match_parent" android:layout_height="150dp"> <ImageView android:src="@drawable/ic_launcher" android:id="@+id/id_img1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:src="@drawable/ic_launcher" android:id="@+id/id_img2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:src="@drawable/ic_launcher" android:id="@+id/id_img3" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </com.example.liuzhiyang.test3d.My3dView>