由于工作需要,今天就使用Camera与Matrix实现3D效果
案例图:
1.自定义View

import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Camera;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;public class ThreeDLayout extends ViewGroup {  private Camera mCamera;  private Matrix mMatrix;  //this viewgroup's center  private int mCenterX;  private int mCenterY;  //rotateDegree  private float mCanvasRotateY;  private float mCanvasRotateX;  private float mCanvasMaxRotateDegree = 50;  //the touch mode  public static int MODE_X = 0;  public static int MODE_Y = 1;  public static int MODE_BOTH_X_Y = 2;  private int mMode = MODE_BOTH_X_Y;  private float mDensity;  private float[] mValues = new float[9];  //the flag of touch  private boolean isCanTouch = false;  //the degree of animation  private float mDegreeY = 0;  private float mDegreeX = 0;  //the flag of animate  private boolean isPlaying = false;  //the degree of longer animate  private int mLoopAnimateY = 0;  public ThreeDLayout(Context context) {    this(context, null);  }  public ThreeDLayout(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  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"));    }    DisplayMetrics dm = new DisplayMetrics();    dm = getResources().getDisplayMetrics();    mDensity = dm.density;    mCamera = new Camera();    mMatrix = new Matrix();  }  @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());  }  @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {    View child = getChildAt(0);    child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());  }  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mCenterX = w / 2;    mCenterY = h / 2;  }  @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);    if (isPlaying) {      mCamera.rotateY(mLoopAnimateY++);      Log.e("wing", mLoopAnimateY + "");      if (mLoopAnimateY == 360) {        mLoopAnimateY = 0;      }      invalidate();    }    mCamera.getMatrix(mMatrix);    // fix the Camera bug,    mMatrix.getValues(mValues);    mValues[6] = mValues[6] / mDensity;    mValues[7] = mValues[7] / mDensity;    mMatrix.setValues(mValues);    mCamera.restore();    mMatrix.preTranslate(-mCenterX, -mCenterY);    mMatrix.postTranslate(mCenterX, mCenterY);    canvas.concat(mMatrix);    super.onDraw(canvas);  }  @Override public boolean onInterceptTouchEvent(MotionEvent ev) {    if (isCanTouch) {      return true;    } else {      return super.onInterceptTouchEvent(ev);    }  }  @Override public boolean onTouchEvent(MotionEvent event) {    if (isCanTouch) {      float x = event.getX();      float y = event.getY();      int action = event.getAction();      switch (action) {        case MotionEvent.ACTION_MOVE: {          rotateCanvasWhenMove(x, y);          invalidate();          return true;        }        case MotionEvent.ACTION_UP: {          mDegreeY = 0;          rotateCanvasWhenMove(mCenterX, mCenterY);          invalidate();          return true;        }      }      return true;    } else {      return super.onTouchEvent(event);    }  }  /**   * get the value to rotate   */  private void rotateCanvasWhenMove(float x, float y) {    float dx = x - mCenterX;    float dy = y - mCenterY;    float percentX = dx / mCenterX;    float percentY = dy / mCenterY;    if (percentX > 1f) {      percentX = 1f;    } else if (percentX < -1f) {      percentX = -1f;    }    if (percentY > 1f) {      percentY = 1f;    } else if (percentY < -1f) {      percentY = -1f;    }    mCanvasRotateY = mCanvasMaxRotateDegree * percentX;    mCanvasRotateX = -(mCanvasMaxRotateDegree * percentY);  }  public void setTouchable(boolean canTouch) {    isCanTouch = canTouch;  }  public void setTouchMode(int mode) {    mMode = mode;    isCanTouch = true;  }  /**   * set the max rotate degree   */  public void setMaxRotateDegree(int degree) {    mCanvasMaxRotateDegree = degree;  }  /**   * start horizontal turn animate   */  public void startHorizontalAnimate(long duration) {    final 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();  }  /**   * start horizontal turn animate delayed   */  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();  }  /**   * start vertical turn animate   */  public void startVerticalAnimate(long duration) {    final ValueAnimator animator = ValueAnimator.ofFloat(-180f, 0f);    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override public void onAnimationUpdate(ValueAnimator animation) {        mDegreeX = (float) animation.getAnimatedValue();        invalidate();      }    });    animator.addListener(new Animator.AnimatorListener() {      @Override public void onAnimationStart(Animator animation) {      }      @Override public void onAnimationEnd(Animator animation) {        mDegreeX = 0;        animator.removeAllUpdateListeners();      }      @Override public void onAnimationCancel(Animator animation) {      }      @Override public void onAnimationRepeat(Animator animation) {      }    });    animator.setDuration(duration);    animator.start();  }  /**   * start vertical turn animate delayed   */  public void startVerticalAnimateDelayed(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() {            startVerticalAnimate(duration);          }        });      }    }).start();  }  /**   * start loop animate   */  public void startHorizontalAnimate() {    isPlaying = true;    invalidate();  }  /**   * stop the loop animate   */  public void stopAnimate() {    isPlaying = false;    mLoopAnimateY = 0;    invalidate();  }}

2.Activity中使用

import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import com.wingsofts.threedlayout.ThreeDLayout;import java.util.ArrayList;import java.util.List;public class WeatherActivity extends AppCompatActivity {  RecyclerView recyclerView;  private Adapter adapter;  private boolean flag = true;  List<String> list = new ArrayList<>();  @Override protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_weather);    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);    list.add("周日");    list.add("周一");    list.add("周二");    list.add("周三");    list.add("周四");    list.add("周五");    list.add("周六");    adapter = new Adapter(list);    recyclerView.setAdapter(adapter);    recyclerView.setLayoutManager(new LinearLayoutManager(this));    ThreeDLayout layout = (ThreeDLayout) findViewById(R.id.td_header);    layout.setTouchable(true);    layout.setTouchMode(ThreeDLayout.MODE_BOTH_X_Y);  }  public void onClick(View v){    ThreeDLayout layout = (ThreeDLayout) findViewById(R.id.td_header);    if(!flag){      flag = true;      ((TextView)findViewById(R.id.textView)).setText("72℉");    }else {      flag = false;      ((TextView)findViewById(R.id.textView)).setText("30℃");    }    layout.startHorizontalAnimate(1000);    for(int i = 0;i<list.size();i++){      ((ThreeDLayout)recyclerView.getChildAt(i)).startHorizontalAnimateDelayed(100*i,1000);    }  }  class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {    List<String> list;    public Adapter(List<String> list) {      this.list = list;    }    @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {      return new MyViewHolder(          LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false));    }    @Override public void onBindViewHolder(Adapter.MyViewHolder holder, int position) {      holder.textView.setText(list.get(position));    }    @Override public int getItemCount() {      return list.size();    }    class MyViewHolder extends RecyclerView.ViewHolder {      TextView textView;      TextView temperatureTxt;      MyViewHolder(View itemView) {        super(itemView);        textView = (TextView) itemView.findViewById(R.id.textView);        temperatureTxt = (TextView) itemView.findViewById(R.id.tv_temperature);      }    }  }}

3.activity_weather.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout 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"    android:orientation="vertical"    tools:context="com.wingsofts.myapplication.WeatherActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <com.wingsofts.threedlayout.ThreeDLayout            android:id="@+id/td_header"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:background="@color/colorPrimary">            <TextView                android:id="@+id/textView"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:gravity="center"                android:text="30℃"                android:textColor="#fff"                android:textSize="80sp" />        </com.wingsofts.threedlayout.ThreeDLayout>        <com.wingsofts.myapplication.MyRecyclerView            android:id="@+id/recyclerView"            android:layout_width="match_parent"            android:layout_height="wrap_content" />        <Button            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:onClick="onClick"            android:text="START" />    </LinearLayout></LinearLayout>

item_main.xml

<?xml version="1.0" encoding="utf-8"?><com.wingsofts.threedlayout.ThreeDLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:background="@color/colorPrimary"    android:layout_width="match_parent"    android:layout_height="wrap_content"    >  <LinearLayout      android:background="@color/colorPrimary"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="horizontal"      android:padding="16dp"      >    <TextView        android:id="@+id/textView"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"        android:gravity="left"        android:textColor="#fff"        android:textSize="16sp"        />    <TextView        android:id="@+id/tv_temperature"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="30℃"        android:textColor="#fff"        android:textSize="16sp"        />  </LinearLayout></com.wingsofts.threedlayout.ThreeDLayout>

更多相关文章

  1. 箭头函数的基础使用
  2. python起点网月票榜字体反爬案例
  3. NPM 和webpack 的基础使用
  4. Python list sort方法的具体使用
  5. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  6. Android(安卓)Activity界面切换添加动画特效
  7. android 使用html5作布局文件: webview跟javascript交互
  8. Android(安卓)Resource介绍和使用
  9. "Failed to fetch URL https://dl-ssl.google.com/android/repos

随机推荐

  1. 菜鸟窝-仿京东淘宝项目学习笔记(二)ToolBar
  2. MediaPlayer源码存在的内存泄漏问题,释放
  3. Android进程间(IPC机制)通信(Bundler,Messe
  4. 从零开始的Android新项目10 - React Nati
  5. Android自定义控件---打造不一样的FlowLa
  6. Android中bindService的细节之二:从进程的
  7. 微信抢红包插件与Android辅助功能
  8. Android开发之MOB短信验证SDK的使用(二)
  9. Android 调用摄像头录视频,用前摄像头预览
  10. Toast显示过程详解