本文主要讲解利用android中Matrix控制图形的旋转缩放移动,具体参见一下代码:
复制代码 代码如下:
/**
* 使用矩阵控制图片移动、缩放、旋转
*/
public class CommonImgEffectView extends View {
private Context context ;
private Bitmap mainBmp , controlBmp ;
private int mainBmpWidth , mainBmpHeight , controlBmpWidth , controlBmpHeight ;
private Matrix matrix ;
private float [] srcPs , dstPs ;
private RectF srcRect , dstRect ;
private Paint paint ,paintRect , paintFrame;
private float deltaX = 0, deltaY = 0; //位移值
private float scaleValue = 1; //缩放值
private Point lastPoint ;
private Point prePivot , lastPivot;
private float preDegree , lastDegree ;
private short currentSelectedPointindex; //当前操作点击点
private Point symmetricPoint = new Point(); //当前操作点对称点
/**
* 图片操作类型
*/
public static final int OPER_DEFAULT = -1; //默认
public static final int OPER_TRANSLATE = 0; //移动
public static final int OPER_SCALE = 1; //缩放
public static final int OPER_ROTATE = 2; //旋转
public static final int OPER_SELECTED = 3; //选择
public int lastOper = OPER_DEFAULT;
/* 图片控制点
* 0---1---2
* | |
* 7 8 3
* | |
* 6---5---4
*/
public static final int CTR_NONE = -1;
public static final int CTR_LEFT_TOP = 0;
public static final int CTR_MID_TOP = 1;
public static final int CTR_RIGHT_TOP = 2;
public static final int CTR_RIGHT_MID = 3;
public static final int CTR_RIGHT_BOTTOM = 4;
public static final int CTR_MID_BOTTOM = 5;
public static final int CTR_LEFT_BOTTOM = 6;
public static final int CTR_LEFT_MID = 7;
public static final int CTR_MID_MID = 8;
public int current_ctr = CTR_NONE;
public CommonImgEffectView(Context context){
super(context);
this.context = context ;
}
public CommonImgEffectView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context ;
initData();
}
/**
* 初始化数据
* @author 张进
*/
private void initData(){
mainBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.flower);
controlBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.control);
mainBmpWidth = mainBmp.getWidth();
mainBmpHeight = mainBmp.getHeight();
controlBmpWidth = controlBmp.getWidth();
controlBmpHeight = controlBmp.getHeight();
srcPs = new float[]{
0,0,
mainBmpWidth/2,0,
mainBmpWidth,0,
mainBmpWidth,mainBmpHeight/2,
mainBmpWidth,mainBmpHeight,
mainBmpWidth/2,mainBmpHeight,
0,mainBmpHeight,
0,mainBmpHeight/2,
mainBmpWidth/2,mainBmpHeight/2
};
dstPs = srcPs.clone();
srcRect = new RectF(0, 0, mainBmpWidth, mainBmpHeight);
dstRect = new RectF();
matrix = new Matrix();
prePivot = new Point(mainBmpWidth/2, mainBmpHeight/2);
lastPivot = new Point(mainBmpWidth/2, mainBmpHeight/2);
lastPoint = new Point(0,0);
paint = new Paint();
paintRect = new Paint();
paintRect.setColor(Color.RED);
paintRect.setAlpha(100);
paintRect.setAntiAlias(true);
paintFrame = new Paint();
paintFrame.setColor(Color.GREEN);
paintFrame.setAntiAlias(true);
setMatrix(OPER_DEFAULT);
}
/**
* 矩阵变换,达到图形平移的目的
* @author 张进
*/
private void setMatrix(int operationType){
switch (operationType) {
case OPER_TRANSLATE:
matrix.postTranslate(deltaX , deltaY);
break;
case OPER_SCALE:
matrix.postScale(scaleValue, scaleValue, symmetricPoint.x, symmetricPoint.y);
break;
case OPER_ROTATE:
matrix.postRotate(preDegree - lastDegree, dstPs[CTR_MID_MID * 2], dstPs[CTR_MID_MID * 2 + 1]);
break;
}
matrix.mapPoints(dstPs, srcPs);
matrix.mapRect(dstRect, srcRect);
}
private boolean isOnPic(int x , int y){
if(dstRect.contains(x, y)){
return true;
}else
return false;
}
private int getOperationType(MotionEvent event){
int evX = (int)event.getX();
int evY = (int)event.getY();
int curOper = lastOper;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
current_ctr = isOnCP(evX, evY);
Log.i("img", "current_ctr is "+current_ctr);
if(current_ctr != CTR_NONE || isOnPic(evX, evY)){
curOper = OPER_SELECTED;
}
break;
case MotionEvent.ACTION_MOVE:
if(current_ctr > CTR_NONE && current_ctr < CTR_MID_MID ){
curOper = OPER_SCALE;
}else if(current_ctr == CTR_MID_MID ){
curOper = OPER_ROTATE;
}else if(lastOper == OPER_SELECTED){
curOper = OPER_TRANSLATE;
}
break;
case MotionEvent.ACTION_UP:
curOper = OPER_SELECTED;
break;
default:
break;
}
Log.d("img", "curOper is "+curOper);
return curOper;
}
/**
* 判断点所在的控制点
* @param evX
* @param evY
* @return
*/
private int isOnCP(int evx, int evy) {
Rect rect = new Rect(evx-controlBmpWidth/2,evy-controlBmpHeight/2,evx+controlBmpWidth/2,evy+controlBmpHeight/2);
int res = 0 ;
for (int i = 0; i < dstPs.length; i+=2) {
if(rect.contains((int)dstPs[i], (int)dstPs[i+1])){
return res ;
}
++res ;
}
return CTR_NONE;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int evX = (int)event.getX();
int evY = (int)event.getY();
int operType = OPER_DEFAULT;
operType = getOperationType(event);
switch (operType) {
case OPER_TRANSLATE:
translate(evX, evY);
break;
case OPER_SCALE:
scale(event);
break;
case OPER_ROTATE:
rotate(event);
break;
}
lastPoint.x = evX;
lastPoint.y = evY;
lastOper = operType;
invalidate();//重绘
return true;
}
/**
* 移动
* @param evx
* @param evy
* @author zhang_jin1
*/
private void translate(int evx , int evy){
prePivot.x += evx - lastPoint.x;
prePivot.y += evy -lastPoint.y;
deltaX = prePivot.x - lastPivot.x;
deltaY = prePivot.y - lastPivot.y;
lastPivot.x = prePivot.x;
lastPivot.y = prePivot.y;
setMatrix(OPER_TRANSLATE); //设置矩阵
}
/**
* 缩放
* 0---1---2
* | |
* 7 8 3
* | |
* 6---5---4
* @param evX
* @param evY
*/
private void scale(MotionEvent event) {
int pointIndex = current_ctr*2 ;
float px = dstPs[pointIndex];
float py = dstPs[pointIndex+1];
float evx = event.getX();
float evy = event.getY();
float oppositeX = 0 ;
float oppositeY = 0 ;
if(current_ctr<4 && current_ctr >= 0){
oppositeX = dstPs[pointIndex+8];
oppositeY = dstPs[pointIndex+9];
}else if(current_ctr >= 4){
oppositeX = dstPs[pointIndex-8];
oppositeY = dstPs[pointIndex-7];
}
float temp1 = getDistanceOfTwoPoints(px,py,oppositeX,oppositeY);
float temp2 = getDistanceOfTwoPoints(evx,evy,oppositeX,oppositeY);
this.scaleValue = temp2 / temp1 ;
symmetricPoint.x = (int) oppositeX;
symmetricPoint.y = (int)oppositeY;
Log.i("img", "scaleValue is "+scaleValue);
setMatrix(OPER_SCALE);
}
/**
* 旋转图片
* 0---1---2
* | |
* 7 8 3
* | |
* 6---5---4
* @param evX
* @param evY
*/
private void rotate(MotionEvent event) {
if(event.getPointerCount() == 2){
preDegree = computeDegree(new Point((int)event.getX(0), (int)event.getY(0)), new Point((int)event.getX(1), (int)event.getY(1)));
}else{
preDegree = computeDegree(new Point((int)event.getX(), (int)event.getY()), new Point((int)dstPs[16], (int)dstPs[17]));
}
setMatrix(OPER_ROTATE);
lastDegree = preDegree;
}
/**
* 计算两点与垂直方向夹角
* @param p1
* @param p2
* @return
*/
public float computeDegree(Point p1, Point p2){
float tran_x = p1.x - p2.x;
float tran_y = p1.y - p2.y;
float degree = 0.0f;
float angle = (float)(Math.asin(tran_x/Math.sqrt(tran_x*tran_x + tran_y* tran_y))*180/Math.PI);
if(!Float.isNaN(angle)){
if(tran_x >= 0 && tran_y <= 0){//第一象限
degree = angle;
}else if(tran_x <= 0 && tran_y <= 0){//第二象限
degree = angle;
}else if(tran_x <= 0 && tran_y >= 0){//第三象限
degree = -180 - angle;
}else if(tran_x >= 0 && tran_y >= 0){//第四象限
degree = 180 - angle;
}
}
return degree;
}
/**
* 计算两个点之间的距离
* @param p1
* @param p2
* @return
*/
private float getDistanceOfTwoPoints(Point p1, Point p2){
return (float)(Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)));
}
private float getDistanceOfTwoPoints(float x1,float y1,float x2,float y2){
return (float)(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}
@Override
public void onDraw(Canvas canvas){
drawBackground(canvas);//绘制背景,以便测试矩形的映射
canvas.drawBitmap(mainBmp, matrix, paint);//绘制主图片
drawFrame(canvas);//绘制边框,以便测试点的映射
drawControlPoints(canvas);//绘制控制点图片
}
private void drawBackground(Canvas canvas){
canvas.drawRect(dstRect, paintRect);
}
private void drawFrame(Canvas canvas){
canvas.drawLine(dstPs[0], dstPs[1], dstPs[4], dstPs[5], paintFrame);
canvas.drawLine(dstPs[4], dstPs[5], dstPs[8], dstPs[9], paintFrame);
canvas.drawLine(dstPs[8], dstPs[9], dstPs[12], dstPs[13], paintFrame);
canvas.drawLine(dstPs[0], dstPs[1], dstPs[12], dstPs[13], paintFrame);
canvas.drawPoint(dstPs[16], dstPs[17], paintFrame);
}
private void drawControlPoints(Canvas canvas){
for (int i = 0; i < dstPs.length; i+=2) {
canvas.drawBitmap(controlBmp, dstPs[i]-controlBmpWidth/2, dstPs[i+1]-controlBmpHeight/2, paint);
}
}
}
Demo效果:
相关推荐:
2024年AI写文章生成器推荐:让创作轻松高效,提升写作水平
AI助手Stut:智能时代的创新引擎,开启未来工作新篇章,ai对ai的格斗游戏
怎么用AI写出令人惊叹的文章?轻松搞定写作难题!
AI写作技巧,让创作事半功倍!
SEO王:掌控搜索引擎优化的至高法则,助力企业飞速腾飞,网站动作优化在哪里下载
SEO收集:如何通过有效数据收集提升网站排名,鞍山商城网站建设报价
SEO出来,打破流量瓶颈,助力企业增长的关键策略,南昌营销推广代理商电话
seo需要保持什么心态,seo的要求 ,ai83562
ChatGPT回答问题,网页无法线下滚动?解决方案轻松get!,谷歌AI铃声
SEO优化基础:让你的网站脱颖而出的秘密武器,模仿猫ai
ChatGPT不能访问,我的学术水平直线下降,泰州大数据ai艾灸价格
SEO但是,这些常见误区你真的知道吗?,凤岗网站建设开发
SEO文案:如何通过巧妙布局提升网站排名,吸引更多流量,娄底网站建设工作文案
SEO希望:如何通过SEO优化实现网站突破,迈向成功之路,品牌网站推广软件
seo网络推广是什么,seo网络推广是什么意思 ,ai哪里注音
ChatGPTDNS出问题?如何快速解决并保障网络畅通,墨镜ai照片
文章AI生成:让创作变得更简单、更高效!
AI提炼主要内容:如何让信息更精准、高效、易懂,女军人ai
在线AI文章:为您打造全新内容创作体验
OpenAI注册问题解决方案:如何顺利通过手机号验证,反对ai头像
SEO监控:精准把握网站排名与优化成效的利器,湖南seo排名商家名单
打造内容创作新高度:文章扩写AI的革命性优势
优化服务网-提升客户体验,打造全方位智慧服务平台,东莞网站建设员招聘信息
SEO关键词利器:如何借助精准关键词提升网站流量与排名,ai绘画客户
AI网页版智能问答,开启智慧沟通新时代,ai梦境档案用不了手柄
ChatGPT国内版:为中国用户量身定制的智能助手,开启AI新纪元,ai文章赚钱
SEO自行:提升网站流量的秘密武器,邹平县个人网站建设建议
中国AI软实力崛起:技术创新与产业应用的完美融合,seo0066
为什么做seo的人很少,为了什么做seo ,ai不负你
“更加通顺”-让生活与工作无缝衔接的语言魅力,SEO书架书桌收纳
ZBlog:开启你的个人网站新时代,轻松搭建与管理,二手手机营销推广方案
AI一键生成原创文章,让创作更高效更轻松!
文章AI生成标题:让创作更轻松,内容更精彩
Chatttst:开启智能沟通新时代的无限可能,上海联通ai
SEO分类中内部优化的有:让你的网站脱颖而出!,by ai
ChatGPT免费用户每天的使用限制:如何高效利用,突破困境!,花花制作ai
ChatGPT服务异常:为何影响到你的工作和生活?如何有效解决?,ai怎么保持圆角不变
SEO教研:数字营销新趋势,提升网站流量与转化率的关键,齐鲁证券网站建设
SEO是什么意思?揭秘SEO的真正含义与重要性,公司推广网站询问d火18星来
SEO搜索关键词是什么意思?全方位解析关键词优化的核心要素,lol ai图片
用AI征文工具,轻松创作出精彩文章!
用AI修改文章,提升写作效率与质量的新时代
为什么要seo排名,为什么要做seo推广 ,AI写作开启创意新世界
用AI写文,开启创作新时代
ChatGPT服务部分恢复:人工智能助力全新体验,ai对象菜单
seo软件工具,seo软件是什么 ,AI妆容
SEO是如何推动企业增长的关键力量,深圳罗湖网站建设设计
为什么选择老域名注册,打造品牌价值的秘密武器,网站建设服务费用多少
seo用什么法宝,列出5种seo赚钱方式 ,ai怎么更改文档样式
仿写AI:智能时代的创作革命,洛江区移动房网站推广