package com.app.fantasticbaby;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.RelativeLayout;
/**
* @author 作者 E-mail:
* @version 创建时间:2016-5-30 下午5:57:05
* 类说明
*/
public class BottomAndTopView extends RelativeLayout {
private ImageView bottomIv;
private ImageView topIv;
private Drawable backgroud;
private Drawable bottomDrawable;
private Drawable topDrawable;
private LayoutParams buttomParams;
private LayoutParams topParams;
Matrix matrixTop = new Matrix();
Matrix savedMatrixTop = new Matrix();
Matrix matrixBottom = new Matrix();
Matrix savedMatrixBottom = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int ROATE = 3;
static final float MAX_SCALE = 2.0f;
static final float MIN_SCALE = 0.5f;
static float currentScale = 1.0f;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float x_down = 0;
float y_down = 0;
float cx_down = 0;
float cy_down = 0;
private float degree;// 偏转角度
Point centerPoint = new Point();
float centerX;
float centerY;
private RelativeLayout rLayout;
@SuppressLint("NewApi")
public BottomAndTopView(Context context, AttributeSet attrs) {
super(context, attrs);
rLayout = this;
// 自定义属性获取
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.customView);
bottomDrawable = ta.getDrawable(R.styleable.customView_bottomRes);
topDrawable = ta.getDrawable(R.styleable.customView_topRes);
backgroud = ta.getDrawable(R.styleable.customView_backgroud);
ta.recycle();
setBackground(backgroud);
// 设置属性值
bottomIv = new ImageView(context);
bottomIv.setImageDrawable(bottomDrawable);
// 设置属性值
topIv = new ImageView(context);
topIv.setImageDrawable(topDrawable);
// 设置底部图片规则
buttomParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
buttomParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
bottomIv.setScaleType(ScaleType.CENTER_INSIDE);
addView(bottomIv, buttomParams);
bottomIv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
bottomIv.setScaleType(ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.w("FLAG", "ACTION_DOWN");
x_down = event.getX();
y_down = event.getY();
matrixBottom.set(bottomIv.getImageMatrix());
savedMatrixBottom.set(matrixBottom);
start.set(x_down, y_down);
mode = ROATE;
break;
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ROATE) {
// 更新中心坐标
updateCenterPoint(topIv);
matrixBottom.set(savedMatrixBottom);
resetPointAngle();
matrixBottom.postRotate(degree,
bottomIv.getWidth() / 2,
bottomIv.getHeight() / 2);// 旋轉();
}
break;
}
bottomIv.setImageMatrix(matrixBottom);
return true;
}
});
// 设置上层图片规则
topParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
topParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
topIv.setScaleType(ScaleType.CENTER_INSIDE);
addView(topIv, topParams);
topIv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
topIv.setScaleType(ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.w("FLAG", "ACTION_DOWN");
x_down = event.getX();
y_down = event.getY();
matrixTop.set(topIv.getImageMatrix());
savedMatrixTop.set(matrixTop);
start.set(x_down, y_down);
// 更新中心坐标
updateCenterPoint(topIv);
if (Math.abs(centerX - x_down) < 40
&& Math.abs(centerY - y_down) < 40) {
mode = DRAG;
} else {
mode = ROATE;
}
break;
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ROATE) {
// 更新中心坐标
updateCenterPoint(topIv);
matrixTop.set(savedMatrixTop);
resetPointAngle();
matrixTop.postRotate(degree, topIv.getWidth() / 2,
topIv.getHeight() / 2);// 旋轉();
topIv.setImageMatrix(matrixTop);
} else if (mode == DRAG) {
// 更新中心坐标
rLayout.setTranslationX(cx_down - start.x);
rLayout.setTranslationY(cy_down - start.y);
}
break;
}
return true;
}
});
}
@SuppressLint("NewApi")
@Override
public boolean onTouchEvent(MotionEvent event) {
this.topIv.setScaleType(ScaleType.MATRIX);
this.bottomIv.setScaleType(ScaleType.MATRIX);
float scale = 0;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
scale = newDist / oldDist;
this.setScaleX(scale);
this.setScaleY(scale);
}
}
break;
}
topIv.setImageMatrix(matrixTop);
bottomIv.setImageMatrix(matrixBottom);
return true;
}
/**
* 更新转盘中心坐标
*/
@SuppressLint("NewApi")
private void updateCenterPoint(ImageView view) {
centerPoint.x = view.getLeft() + view.getWidth() / 2;
// // 当前图片中心纵坐标
centerPoint.y = view.getTop() + view.getHeight() / 2;
// 获取imageview控件中图片实际坐标
Matrix matrix = view.getMatrix();
float[] value = new float[9];
matrix.getValues(value);
// view.getDrawable().getBounds().width() 2 获得imageview中图片之际宽度
centerX = value[2] + view.getDrawable().getBounds().width() / 2;
// // // 当前图片中心纵坐标
centerY = value[5] + view.getDrawable().getBounds().height() / 2;
}
/**
*
* 方法名:resetPointAngle 功能:重新计算每个点的角度 参数:
*
*/
private void resetPointAngle() {
// 每次转动的角度
degree = computeMigrationAngle();
}
/**
*
* 方法名:computeMigrationAngle 功能:计算偏移角度 参数: 每次转动的角度差
*/
private float computeMigrationAngle() {
/**
* Math.PI 记录的圆周率 Math.E记录e的常量 Math.abs 求绝对值 Math.sin 正弦函数
* Math.asin反正弦函数 Math.cos 余弦函数 Math.acos 反余弦函数 Math.tan 正切函数 Math.atan
* 反正切函数 Math.atan2 商的反正切函数 Math.toDegrees 弧度转化为角度 Math.toRadians
* 角度转化为弧度 Math.ceil 得到不小于某数的最大整数 Math.floor 得到不大于某数的最大整数
*/
return (float) (Math.toDegrees(Math.atan2(cy_down - centerPoint.y,
cx_down - centerPoint.x)) - Math.toDegrees(Math.atan2(y_down
- centerPoint.y, x_down - centerPoint.x)));
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean isIntercept = false;
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(ev);
if (oldDist > 10f) {
savedMatrixTop.set(matrixTop);
savedMatrixBottom.set(matrixBottom);
midPoint(mid, ev);
mode = ZOOM;
}
isIntercept = true;
break;
}
return isIntercept;
}
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.RelativeLayout;
/**
* @author 作者 E-mail:
* @version 创建时间:2016-5-30 下午5:57:05
* 类说明
*/
public class BottomAndTopView extends RelativeLayout {
private ImageView bottomIv;
private ImageView topIv;
private Drawable backgroud;
private Drawable bottomDrawable;
private Drawable topDrawable;
private LayoutParams buttomParams;
private LayoutParams topParams;
Matrix matrixTop = new Matrix();
Matrix savedMatrixTop = new Matrix();
Matrix matrixBottom = new Matrix();
Matrix savedMatrixBottom = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int ROATE = 3;
static final float MAX_SCALE = 2.0f;
static final float MIN_SCALE = 0.5f;
static float currentScale = 1.0f;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float x_down = 0;
float y_down = 0;
float cx_down = 0;
float cy_down = 0;
private float degree;// 偏转角度
Point centerPoint = new Point();
float centerX;
float centerY;
private RelativeLayout rLayout;
@SuppressLint("NewApi")
public BottomAndTopView(Context context, AttributeSet attrs) {
super(context, attrs);
rLayout = this;
// 自定义属性获取
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.customView);
bottomDrawable = ta.getDrawable(R.styleable.customView_bottomRes);
topDrawable = ta.getDrawable(R.styleable.customView_topRes);
backgroud = ta.getDrawable(R.styleable.customView_backgroud);
ta.recycle();
setBackground(backgroud);
// 设置属性值
bottomIv = new ImageView(context);
bottomIv.setImageDrawable(bottomDrawable);
// 设置属性值
topIv = new ImageView(context);
topIv.setImageDrawable(topDrawable);
// 设置底部图片规则
buttomParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
buttomParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
bottomIv.setScaleType(ScaleType.CENTER_INSIDE);
addView(bottomIv, buttomParams);
bottomIv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
bottomIv.setScaleType(ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.w("FLAG", "ACTION_DOWN");
x_down = event.getX();
y_down = event.getY();
matrixBottom.set(bottomIv.getImageMatrix());
savedMatrixBottom.set(matrixBottom);
start.set(x_down, y_down);
mode = ROATE;
break;
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ROATE) {
// 更新中心坐标
updateCenterPoint(topIv);
matrixBottom.set(savedMatrixBottom);
resetPointAngle();
matrixBottom.postRotate(degree,
bottomIv.getWidth() / 2,
bottomIv.getHeight() / 2);// 旋轉();
}
break;
}
bottomIv.setImageMatrix(matrixBottom);
return true;
}
});
// 设置上层图片规则
topParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
topParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
topIv.setScaleType(ScaleType.CENTER_INSIDE);
addView(topIv, topParams);
topIv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
topIv.setScaleType(ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.w("FLAG", "ACTION_DOWN");
x_down = event.getX();
y_down = event.getY();
matrixTop.set(topIv.getImageMatrix());
savedMatrixTop.set(matrixTop);
start.set(x_down, y_down);
// 更新中心坐标
updateCenterPoint(topIv);
if (Math.abs(centerX - x_down) < 40
&& Math.abs(centerY - y_down) < 40) {
mode = DRAG;
} else {
mode = ROATE;
}
break;
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ROATE) {
// 更新中心坐标
updateCenterPoint(topIv);
matrixTop.set(savedMatrixTop);
resetPointAngle();
matrixTop.postRotate(degree, topIv.getWidth() / 2,
topIv.getHeight() / 2);// 旋轉();
topIv.setImageMatrix(matrixTop);
} else if (mode == DRAG) {
// 更新中心坐标
rLayout.setTranslationX(cx_down - start.x);
rLayout.setTranslationY(cy_down - start.y);
}
break;
}
return true;
}
});
}
@SuppressLint("NewApi")
@Override
public boolean onTouchEvent(MotionEvent event) {
this.topIv.setScaleType(ScaleType.MATRIX);
this.bottomIv.setScaleType(ScaleType.MATRIX);
float scale = 0;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
Log.w("FLAG", "ACTION_UP");
case MotionEvent.ACTION_POINTER_UP:
Log.w("FLAG", "ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
cx_down = event.getX();
cy_down = event.getY();
Log.w("FLAG", "ACTION_MOVE");
if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
scale = newDist / oldDist;
this.setScaleX(scale);
this.setScaleY(scale);
}
}
break;
}
topIv.setImageMatrix(matrixTop);
bottomIv.setImageMatrix(matrixBottom);
return true;
}
/**
* 更新转盘中心坐标
*/
@SuppressLint("NewApi")
private void updateCenterPoint(ImageView view) {
centerPoint.x = view.getLeft() + view.getWidth() / 2;
// // 当前图片中心纵坐标
centerPoint.y = view.getTop() + view.getHeight() / 2;
// 获取imageview控件中图片实际坐标
Matrix matrix = view.getMatrix();
float[] value = new float[9];
matrix.getValues(value);
// view.getDrawable().getBounds().width() 2 获得imageview中图片之际宽度
centerX = value[2] + view.getDrawable().getBounds().width() / 2;
// // // 当前图片中心纵坐标
centerY = value[5] + view.getDrawable().getBounds().height() / 2;
}
/**
*
* 方法名:resetPointAngle 功能:重新计算每个点的角度 参数:
*
*/
private void resetPointAngle() {
// 每次转动的角度
degree = computeMigrationAngle();
}
/**
*
* 方法名:computeMigrationAngle 功能:计算偏移角度 参数: 每次转动的角度差
*/
private float computeMigrationAngle() {
/**
* Math.PI 记录的圆周率 Math.E记录e的常量 Math.abs 求绝对值 Math.sin 正弦函数
* Math.asin反正弦函数 Math.cos 余弦函数 Math.acos 反余弦函数 Math.tan 正切函数 Math.atan
* 反正切函数 Math.atan2 商的反正切函数 Math.toDegrees 弧度转化为角度 Math.toRadians
* 角度转化为弧度 Math.ceil 得到不小于某数的最大整数 Math.floor 得到不大于某数的最大整数
*/
return (float) (Math.toDegrees(Math.atan2(cy_down - centerPoint.y,
cx_down - centerPoint.x)) - Math.toDegrees(Math.atan2(y_down
- centerPoint.y, x_down - centerPoint.x)));
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean isIntercept = false;
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(ev);
if (oldDist > 10f) {
savedMatrixTop.set(matrixTop);
savedMatrixBottom.set(matrixBottom);
midPoint(mid, ev);
mode = ZOOM;
}
isIntercept = true;
break;
}
return isIntercept;
}
}
布局文件:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@drawable/back1" >
<com.app.fantasticbaby.BottomAndTopView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:bottomRes="@drawable/back2"
custom:topRes="@drawable/back3" />
</LinearLayout>