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

来源:互联网 发布:mac finder 打开路径 编辑:程序博客网 时间:2024/04/28 13:15

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

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


效果预览

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

这里写图片描述这里写图片描述这里写图片描述


如何导入ThreeDLayout

方式一

在gralde下加入compile('com.wingsofts.threedlayout:1.0.0')(还没上传到远程仓库,会于近日上传)

方式二

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

如何使用

以Demo中天气Activity为例。

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

<LinearLayout    android:orientation="vertical"    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/threeDLayout"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.wingsofts.myapplication.WeatherActivity"    ><LinearLayout    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    >   <TextView       android:id="@+id/textView"      android:text="30℃"      android:textColor="#fff"      android:gravity="center"      android:textSize="80sp"      android:layout_width="match_parent"      android:layout_height="wrap_content"      />  <com.wingsofts.myapplication.MyRecyclerView      android:id="@+id/recyclerView"      android:layout_width="match_parent"      android:layout_height="wrap_content"      /></LinearLayout></LinearLayout>

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

<com.wingsofts.threedlayout.ThreeDLayout      android:background="@color/colorPrimary"      android:id="@+id/td_header"      android:layout_width="match_parent"      android:layout_height="wrap_content"      >   <TextView       android:id="@+id/textView"      android:text="30℃"      android:textColor="#fff"      android:gravity="center"      android:textSize="80sp"      android:layout_width="match_parent"      android:layout_height="wrap_content"      />  </com.wingsofts.threedlayout.ThreeDLayout>

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

    ThreeDLayout layout = (ThreeDLayout) findViewById(R.id.td_header);    //开启触摸模式    layout.setTouchable(true);    //设置模式为X,Y轴旋转    layout.setTouchMode(ThreeDLayout.MODE_BOTH_X_Y);

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

//开启水平翻转动画startHorizontalAnimate(long duration)//延迟开启水平翻转动画startHorizontalAnimate(long duration,long delayed)

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

  for(int i = 0;i<list.size();i++){      ((ThreeDLayout)recyclerView.getChildAt(i)).startHorizontalAnimateDelayed(100*i,1000);    }

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


ThreeDLayout如何实现

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

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

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

@Override protected void onDraw(Canvas canvas) {    mMatrix.reset();    mCamera.save();    mCamera.getMatrix(mMatrix);    mCamera.restore();    mMatrix.preTranslate(-mCenterX, -mCenterY);    mMatrix.postTranslate(mCenterX, mCenterY);    canvas.concat(mMatrix);    super.onDraw(canvas);  }

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

  public ThreeDLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    //set a default background to make sure onDraw() dispatch    if (getBackground() == null) {      setBackgroundColor(Color.parseColor("#ffffff"));    }    mCamera = new Camera();    mMatrix = new Matrix();  }

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

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    if (getChildCount() != 1) {      throw new IllegalStateException("ThreeDLayout can only have one child");    }    View child = getChildAt(0);    measureChild(child, widthMeasureSpec, heightMeasureSpec);    //only one child view,so give the same size    setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());  }

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

    if (mMode == MODE_Y || mMode == MODE_BOTH_X_Y) {      mCamera.rotateX(mCanvasRotateX);    }    if (mMode == MODE_X || mMode == MODE_BOTH_X_Y) {      mCamera.rotateY(mCanvasRotateY);    }

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

  @Override protected void onDraw(Canvas canvas) {    mMatrix.reset();    mCamera.save();       if (mMode == MODE_Y || mMode == MODE_BOTH_X_Y) {      mCamera.rotateX(mCanvasRotateX);    }    if (mMode == MODE_X || mMode == MODE_BOTH_X_Y) {      mCamera.rotateY(mCanvasRotateY);    }    mCamera.rotateY(mDegreeY);    mCamera.rotateX(mDegreeX);    }

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

  public void startHorizontalAnimate(long duration){    ValueAnimator animator = ValueAnimator.ofFloat(-180f,0f);    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override public void onAnimationUpdate(ValueAnimator animation) {        mDegreeY = (float) animation.getAnimatedValue();        invalidate();      }    });    animator.addListener(new Animator.AnimatorListener() {      @Override public void onAnimationStart(Animator animation) {      }      @Override public void onAnimationEnd(Animator animation) {        mDegreeY = 0;        animator.removeAllUpdateListeners();      }      @Override public void onAnimationCancel(Animator animation) {      }      @Override public void onAnimationRepeat(Animator animation) {      }    });    animator.setDuration(duration);    animator.start();  }

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

 public void startHorizontalAnimateDelayed(final long delayed, final long duration){    new Thread(new Runnable() {      @Override public void run() {        try {          Thread.sleep(delayed);        } catch (InterruptedException e) {          e.printStackTrace();        }        post(new Runnable() {          @Override public void run() {           startHorizontalAnimate(duration);          }        });      }    }).start();  }

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

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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 外地人在北京怎么办准生证 北京二孩准生证怎么办 在北京办准生证怎么办 北京2胎准生证怎么办 学号密码忘了怎么办 解散qq群不了怎么办 单身公寓晒衣服怎么办 在房间做饭油烟怎么办 两梯7户怎么办 身上有妊娠纹怎么办 小学寄读生学籍怎么办 实在租不到房子怎么办? 回迁房产权到期怎么办 人进看守所之后怎么办 在看守所见不到怎么办 政审爷爷有犯罪怎么办 看守犯人遇到贿赂怎么办 家属收到行政拘留通知书怎么办 有治安处罚记录怎么办 党员被打了怎么办 交通事故第一次笔录不对怎么办 老公被刑拘了怎么办 老公被拘留了怎么办 刑拘看守所不收怎么办 被贷款中介忽悠怎么办 被中介套路贷款怎么办 车牌变更后保险怎么办 被诬陷诈骗刑拘怎么办 把人头打破了怎么办 起诉后找不到人怎么办 欠款人转移财产怎么办 公安不退保释金怎么办 拘留没钱交罚款怎么办 对治安拘留不服 怎么办 老公被治安拘留怎么办 治安拘留找不到人怎么办 刑事拘留转治安拘留怎么办 遇到晦气的事怎么办 人死在看守所怎么办 检察院抗诉了我怎么办 异地在北京怎么办护照