Wrote a blog about customizing 3D Views a long, long time ago. However, it only describes how to implement, implementation is still time-consuming, so in an approachable mentality, it is packaged into a ViewGroup, just need to wrap your view or layout around a layer of ThreeDLayout to achieve 3D effect (after all: nothing is better than using it!!). . This post is synchronized from the blogger’s private blog Wing’s local Tavern

ThreeDLayout project address: github.com/githubwing/…


Results the preview

3D touch effects, rotation effects, and effects with rotation effects

Write the picture description here



How do I import ThreeDLayout

Methods a

Modify your Gradle file


allprojects {
  repositories {
    jcenter()
    maven { url "https://jitpack.io"}}}dependencies {
            compile 'com. Making. Githubwing: ThreeDLayout: 1.0.0'
    }Copy the code

Way 2

Copy threedLayout. Java from the threedLayout folder into your project and use it.

How to use

Take the weather Activity in Demo as an example.

Add a TextView to the XML to display the high temperature, and a RecyclerView to display the daily temperature.

<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>Copy the code

This is a basic interface implementation. How do I get the large temperature display to rotate? Just wrap it with 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>Copy the code

Get the layout in the code and set the touch mode to achieve:


    ThreeDLayout layout = (ThreeDLayout) findViewById(R.id.td_header);
    // Enable touch mode
    layout.setTouchable(true);
    // Set mode to X and Y rotation
    layout.setTouchMode(ThreeDLayout.MODE_BOTH_X_Y);Copy the code

In ThreeDLayout, we provide a way to flip the animation:

// Turn on the flip animation
startHorizontalAnimate(long duration)

// Delay the flip animation

startHorizontalAnimate(long duration,long delayed)Copy the code

So the Item animation is actually a for loop that lets them execute the animation in turn (of course the Item is wrapped with ThreeDLayout):

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

Here, the use of ThreeDLayout has been introduced, is not very simple. If you’re interested, read on to see how ThreeDLayout is implemented.


How does ThreeDLayout work

In a long blog post, I explained how to implement a 3Dview, which I won’t repeat here. Hand in hand to take you to a 3D view

Here’s how to encapsulate the code you write every time. My initial idea is to wrap a ViewGroup directly and override the onDraw() method. = = Yes, it’s that simple.

So I took the 3D View code and rewrote 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);
  }Copy the code

This is probably enough to get the 3D effect, but it doesn’t work. Because viewGroup onDraw() is not normally called. How do you solve it? Instead, let the viewgroup participate in the draw process, so I added a background color to it in the constructor. So with the background color he’s going to call 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();
  }Copy the code

OnMeasure () = onMeasure(); onMeasure() = onMeasure(); onMeasure() = 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());
  }Copy the code

In order to provide different requirements, the extension allows users to set touch mode to be enabled or not, and to set X and Y, so make some judgments in 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);
    }Copy the code

Now a ThreeDLayout is complete. But in order to make him better use it, to add an animation effect, is the horizontal flip animation, so that the practicality of higher, you can achieve a similar effect of weather Activity. So in onDraw() we need an extra layer of rotation control.


  @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);
    }Copy the code

Then provide a method to start the animation, and by the way, when the animation is finished, set degree to 0, so it will be in unflipped state:

  public void startHorizontalAnimate(long duration){
    ValueAnimator animator = ValueAnimator.ofFloat(- 180.f,0f);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override public voidonAnimationUpdate(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();

  }Copy the code

Then provide a method to delay the animation, internal open a thread timer, and then execute the animation method:

 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 voidrun() { startHorizontalAnimate(duration); }}); } }).start(); }Copy the code

If you like my blog, welcome to comment and pay attention to me ~ ThreeDLayout project address: Github.com/githubwing/…

If you’re an Android developer, you can also share your development experience at Wing’s tavern :425983695