当前位置:   article > 正文

5秒让你的View变3D,ThreeDLayout使用和实现

three-d-view-content

在很久很久以前,写了一篇自定义3d view的博客。但是只是讲了如何实现,实现起来还是比较耗时,所以本着平易近人的心态,把他封装成了一个ViewGroup,只需要在你的view或者布局外面包裹一层ThreeDLayout 即可实现3D效果(毕竟:没有什么比拿来就能用更爽的事情了!!)。本文同步自博主的私人博客wing的地方酒馆

ThreeDLayout的项目地址:github.com/githubwing/…


效果预览

3D触摸效果,旋转效果,和用旋转效果实现的特效

这里写图片描述



如何导入ThreeDLayout

方式一

修改你的gradle文件

  1. allprojects {
  2. repositories {
  3. jcenter()
  4. maven { url "https://jitpack.io" }
  5. }
  6. }
  7. dependencies {
  8. compile 'com.github.githubwing:ThreeDLayout:1.0.0'
  9. }复制代码

方式二

将项目地址依赖库 :threedlayout文件夹下ThreeDLayout.java拷贝至你的项目中,即可使用。

如何使用

以Demo中天气Activity为例。

在xml中加入一个TextView,来显示大温度,下面一个RecyclerView,来显示每天的温度。

  1. <LinearLayout
  2. android:orientation="vertical"
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:id="@+id/threeDLayout"
  6. android:layout_width="match_parent"
  7. android:layout_height="match_parent"
  8. tools:context="com.wingsofts.myapplication.WeatherActivity"
  9. >
  10. <LinearLayout
  11. android:orientation="vertical"
  12. android:layout_width="match_parent"
  13. android:layout_height="match_parent"
  14. >
  15. <TextView
  16. android:id="@+id/textView"
  17. android:text="30℃"
  18. android:textColor="#fff"
  19. android:gravity="center"
  20. android:textSize="80sp"
  21. android:layout_width="match_parent"
  22. android:layout_height="wrap_content"
  23. />
  24. <com.wingsofts.myapplication.MyRecyclerView
  25. android:id="@+id/recyclerView"
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content"
  28. />
  29. </LinearLayout>
  30. </LinearLayout>复制代码

这就是一个最基本的界面实现。如何让大温度显示旋转起来呢?只需要用ThreeDlayout将其包裹。

  1. <com.wingsofts.threedlayout.ThreeDLayout
  2. android:background="@color/colorPrimary"
  3. android:id="@+id/td_header"
  4. android:layout_width="match_parent"
  5. android:layout_height="wrap_content"
  6. >
  7. <TextView
  8. android:id="@+id/textView"
  9. android:text="30℃"
  10. android:textColor="#fff"
  11. android:gravity="center"
  12. android:textSize="80sp"
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. />
  16. </com.wingsofts.threedlayout.ThreeDLayout>复制代码

在代码中获取到该layout,并且设置触摸模式,即可实现:

  1. ThreeDLayout layout = (ThreeDLayout) findViewById(R.id.td_header);
  2. //开启触摸模式
  3. layout.setTouchable(true);
  4. //设置模式为X,Y轴旋转
  5. layout.setTouchMode(ThreeDLayout.MODE_BOTH_X_Y);复制代码

接下来讲解item动画实现,可以看到其实item是一个接一个延迟旋转,在ThreeDLayout中提供了翻转动画的方法:

  1. //开启水平翻转动画
  2. startHorizontalAnimate(long duration)
  3. //延迟开启水平翻转动画
  4. startHorizontalAnimate(long duration,long delayed)复制代码

所以Item动画其实是一个for循环,让他们依次执行动画即可~~(当然item要使用ThreeDLayout包裹):

  1. for(int i = 0;i<list.size();i++){
  2. ((ThreeDLayout)recyclerView.getChildAt(i)).startHorizontalAnimateDelayed(100*i,1000);
  3. }复制代码

到这里,ThreeDLayout的使用已经介绍完了,是不是很简单呢。如果你感兴趣,可以继续往下阅读,会介绍ThreeDLayout是如何实现的。


ThreeDLayout如何实现

在很久的一篇博客里,我介绍了如何实现一个3Dview,这里就不重复讲解。手把手带你撸一个3D view

这里主要讲解如何把每次都要写的代码封装起来。 我的初始思路就是直接包裹成一个ViewGroup,重写onDraw()方法即可。= = 没错就是这么简单。

所以我把之前3D view的代码搬运过来了,然后重写了一下onDraw()。

  1. @Override protected void onDraw(Canvas canvas) {
  2. mMatrix.reset();
  3. mCamera.save();
  4. mCamera.getMatrix(mMatrix);
  5. mCamera.restore();
  6. mMatrix.preTranslate(-mCenterX, -mCenterY);
  7. mMatrix.postTranslate(mCenterX, mCenterY);
  8. canvas.concat(mMatrix);
  9. super.onDraw(canvas);
  10. }复制代码

大概是这样就能完成3D的效果了,但是运行起来没卵用。因为viewgroup的onDraw()一般是不会调用的。怎么解决呢?其实让viewgroup参与draw的过程就好啦,于是我在构造器里给他添加了个背景色。有了背景色他就会调用onDraw了。

  1. public ThreeDLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  2. super(context, attrs, defStyleAttr);
  3. //set a default background to make sure onDraw() dispatch
  4. if (getBackground() == null) {
  5. setBackgroundColor(Color.parseColor("#ffffff"));
  6. }
  7. mCamera = new Camera();
  8. mMatrix = new Matrix();
  9. }复制代码

不过事情没有这么简单,还要解决测量问题,于是这里我就取巧,让ThreeDLayout只有一个子view,这样就可以把大小设置成子view的大小,免去测量的过程,所以onMeasure()是这样的:

  1. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. if (getChildCount() != 1) {
  3. throw new IllegalStateException("ThreeDLayout can only have one child");
  4. }
  5. View child = getChildAt(0);
  6. measureChild(child, widthMeasureSpec, heightMeasureSpec);
  7. //only one child view,so give the same size
  8. setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
  9. }复制代码

为了提供不同的需求,所以扩展一下,用户可以自己设置是否开启触摸模式,并且可以设置X,Y,所以在onDraw()里进行一些判断:

  1. if (mMode == MODE_Y || mMode == MODE_BOTH_X_Y) {
  2. mCamera.rotateX(mCanvasRotateX);
  3. }
  4. if (mMode == MODE_X || mMode == MODE_BOTH_X_Y) {
  5. mCamera.rotateY(mCanvasRotateY);
  6. }复制代码

现在一个ThreeDLayout就完成了。可是为了让他更好用呢,要添加一个动画效果,就是水平翻转动画,这样实用性更高,就可以实现天气Activity类似效果。所以在onDraw()里要多加一层旋转角度控制.

  1. @Override protected void onDraw(Canvas canvas) {
  2. mMatrix.reset();
  3. mCamera.save();
  4. if (mMode == MODE_Y || mMode == MODE_BOTH_X_Y) {
  5. mCamera.rotateX(mCanvasRotateX);
  6. }
  7. if (mMode == MODE_X || mMode == MODE_BOTH_X_Y) {
  8. mCamera.rotateY(mCanvasRotateY);
  9. }
  10. mCamera.rotateY(mDegreeY);
  11. mCamera.rotateX(mDegreeX);
  12. }复制代码

然后提供一个动画开始的方法,顺便当动画完成的时候,使degree变为0,这样就会处于不翻转状态:

  1. public void startHorizontalAnimate(long duration){
  2. ValueAnimator animator = ValueAnimator.ofFloat(-180f,0f);
  3. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  4. @Override public void onAnimationUpdate(ValueAnimator animation) {
  5. mDegreeY = (float) animation.getAnimatedValue();
  6. invalidate();
  7. }
  8. });
  9. animator.addListener(new Animator.AnimatorListener() {
  10. @Override public void onAnimationStart(Animator animation) {
  11. }
  12. @Override public void onAnimationEnd(Animator animation) {
  13. mDegreeY = 0;
  14. animator.removeAllUpdateListeners();
  15. }
  16. @Override public void onAnimationCancel(Animator animation) {
  17. }
  18. @Override public void onAnimationRepeat(Animator animation) {
  19. }
  20. });
  21. animator.setDuration(duration);
  22. animator.start();
  23. }复制代码

然后再提供一个延迟动画的方法,内部开一个线程计时,然后去执行动画方法即可:

  1. public void startHorizontalAnimateDelayed(final long delayed, final long duration){
  2. new Thread(new Runnable() {
  3. @Override public void run() {
  4. try {
  5. Thread.sleep(delayed);
  6. } catch (InterruptedException e) {
  7. e.printStackTrace();
  8. }
  9. post(new Runnable() {
  10. @Override public void run() {
  11. startHorizontalAnimate(duration);
  12. }
  13. });
  14. }
  15. }).start();
  16. }复制代码

好啦,大功告成,以上就是ThreeDLayout的实现啦,如果你觉得效果比较cool,或者该控件比较实用,欢迎star一下~ 如果你喜欢我的博客,欢迎评论以及关注我~
ThreeDLayout的项目地址:github.com/githubwing/…

如果你是Android开发者,那么你还可以来 wing的酒馆:425983695
来分享你的开发经验哦

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/433512
推荐阅读
相关标签
  

闽ICP备14008679号