我要介绍的是一个

能旋转的view,说这个view能旋转有点不切实际,那是视觉效果,其实是对图片的旋转。目前它只支持图片。你可以把它认为是一个能响应手势旋转的View。

它的功能有:

1.会响应手势旋转

2.该view模拟真实罗盘旋转:a.旋转的时候会有惯性,继续旋转,而且是减速旋转b.旋转期间手指扳动罗盘,能加速罗盘旋转c.当罗盘在旋转的时候,手指按住罗盘,它会有刹车的效果。

效果截图:

为了形象点我用了一张风车的图作为例子

技术要点

1.需要扩展一个view,重写ondraw(),onTouchEvent(),onMeasure(),onDetachedFromWindow()方法

a.onDraw():主要是控制图片旋转绘图

b.onTouchEvent():主要是监听手势

c.onMeasere():用来测量view的长宽,在xml里最好配置成wrap_content,因为如果为固定值可能会因为长宽不够,导致显示不全

d.onDetachedFromWindow():用来回收bitmap

2.需要通过handler来处理惯性

3.需要一个速度分析器,来分析手势离开时的瞬时速度

4.需要用到圆和三角函数的知识:如反正切函数,弧度等

技术难点分析

1.如何扩展这个View

a.View的旋转图片的设置

我们可以提供一个方法来设置旋转的图片,并定义旋转图片的成员变量,这里我将它命名为rotaBitmap

public void setRotatBitmap(Bitmap bitmap) {

rotatBitmap = bitmap;

initSize();

postInvalidate();

}

public void setRotatDrawableResource(int id) {

BitmapDrawable drawable = (BitmapDrawable)getContext().getResources().getDrawable(id);

setRotatDrawable(drawable);

}

public void setRotatDrawable(BitmapDrawable drawable) {

rotatBitmap = drawable.getBitmap();

initSize();

postInvalidate();

}

b.View长宽确认

有了图片就可以确认这个view的大小了,这里view的大小不是image的大小,因为还要考虑旋转,一个矩形要确保旋转360度都能被看见,那这个区域应该是个正方形,而且这个正方形的内切圆半径是这个矩形的对角线一半。不知道能否说明白,还是我画图吧。

通过上图,应该很容易发现,这个view的长度应该是被旋转图的对角线的长度

这样我们可以加上这样一段代码:

private void initSize() {

if (rotatBitmap == null) {

// throw new NoBitMapError("Error,No bitmap in RotatView!");

return;

}

width = rotatBitmap.getWidth();

height = rotatBitmap.getHeight();

maxwidth = Math.sqrt(width * width + height * height);

o_x = o_y = (float)(maxwidth / 2);//确定圆心坐标

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO Auto-generated method stub

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 它的宽高不是图片的宽高,而是以宽高为直角的矩形的对角线的长度

setMeasuredDimension((int)maxwidth, (int)maxwidth);

}

c.旋转原理

图片的旋转是在ondraw()里实现的,通过一个变量:deta_degree

来控制旋转的度数

/**

* 当前圆盘所转的弧度(以该 view 的中心为圆点)

*/

float deta_degree;

然后用Matrix来控制旋转图片,主要是preRotate(deta_degree)这里的单位是度,360度为一圈,最后把旋转的图画到画布上

@Override

protected void onDraw(Canvas canvas) {

Matrix matrix = new Matrix();

// 设置转轴位置

matrix.setTranslate((float)width / 2, (float)height / 2);

// 开始转

matrix.preRotate(deta_degree);

// 转轴还原

matrix.preTranslate(-(float)width / 2, -(float)height / 2);

// 将位置送到view的中心

matrix.postTranslate((float)(maxwidth - width) / 2, (float)(maxwidth - height) / 2);

canvas.drawBitmap(rotatBitmap, matrix,paint);

super.onDraw(canvas);

}

考虑到它的周期为360,如果detaDegree的度数太大可能会越界,我们可以做一个于求余处理,让它的值在-360到360之间

/**

* 通过此方法来控制旋转度数,如果超过360,让它求余,防止,该值过大造成越界

*

* @param added

*/

private void addDegree(float added) {

deta_degree += added;

if (deta_degree > 360 || deta_degree < -360) {

deta_degree = deta_degree % 360;

}

}

这里的动画是通过不停的走ondraw()方法刷新,产生的效果,类似放电影一样

d.view的手势响应

当用户触摸它时会响应onTouch事件,在onTouch里分析手指的坐标,通过坐标算出与圆心的夹角

下图为手指与view中心的夹角(这里的原点就是view的旋转中心):

每次手指滑动或是松开都会计算它与原点的夹角,这个方法可以通过反正切函数求出来,详情:

/**

* 计算以(src_x,src_y)为坐标圆点,建立直角体系,求出(target_x,target_y)坐标与x轴的夹角

* 主要是利用反正切函数的知识求出夹角

*

* @param src_x

* @param src_y

* @param target_x

* @param target_y

* @return

*/

float detaDegree(float src_x, float src_y, float target_x, float target_y) {

float detaX = target_x - src_x;

float detaY = target_y - src_y;

double d;

//坐标在四个象限里

if (detaX != 0) {

float tan = Math.abs(detaY / detaX);

if (detaX > 0) {

//第一象限

if (detaY >= 0) {

d = Math.atan(tan);

} else {

//第四象限

d = 2 * Math.PI - Math.atan(tan);

}

} else {

if (detaY >= 0) {

//第二象限

d = Math.PI - Math.atan(tan);

} else {

//第三象限

d = Math.PI + Math.atan(tan);

}

}

} else {

//坐标在y轴上

if (detaY > 0) {

//坐标在y>0上

d = Math.PI / 2;

} else {

//坐标在y<0上

d = -Math.PI / 2;

}

}

return (float)((d * 180) / Math.PI);

}

通过以上方法,可以把每次移动的时候的夹角求出来,把当前的夹角和上次的手指夹角坐差运算就能求出手指相对圆心旋转的角度增量,得到这个角度增量就可以通过调用

这前提过的addDegree()方法,改变图片的角度,然后调用invalidate()方法重绘,就实现了罗盘随手指旋转的效果。

在这里赋上ontouch处理down和move事件的代码(up事件是用来处理惯性用的):

@Override

public boolean onTouchEvent(MotionEvent event) {

// TODO Auto-generated method stub

if (rotatBitmap == null) {

throw new NoBitMapError("Error,No bitmap in RotatView!");

}

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN: {

down_x = event.getX();

down_y = event.getY();

current_degree = detaDegree(o_x, o_y, down_x, down_y);

break;

}

case MotionEvent.ACTION_MOVE: {

down_x = target_x = event.getX();

down_y = target_y = event.getY();

float degree = detaDegree(o_x, o_y, target_x, target_y);

// 滑过的弧度增量

float dete = degree - current_degree;

// 如果小于-90度说明 它跨周了,需要特殊处理350->17,

if (dete < -270) {

dete = dete + 360;

// 如果大于90度说明 它跨周了,需要特殊处理-350->-17,

} else if (dete > 270) {

dete = dete - 360;

}

addDegree(dete);

current_degree = degree;

invalidate();

break;

}

e.View的瞬时速度获取

为了得到瞬时速度,我的思路是通过一个固定长度的2维数组,把手指与原点的最近几次夹角增量和时间点记录下来,通过这几个夹角增量和时间点,可以算出平均速度,因为手指滑动的时候,响应ontouch事件次数非常多,我们可以把最后几次ontouch记录下的数据,取平均值,把它认为是瞬时速度。

这里用到了一点物理知识:

假如上图为record记录的4组数据,t代表时间点,表示产生这个事件的时间,d代表手指与圆心夹角的增量,它是这次夹角与上次夹角的差值

这样我们可以把t=t3-t0算出经过的时间,把sum=d1+d2+d3算出这段时间一共经历过的弧度

再把sum/t就是平均速度了

但需要注意一个细节:d0是无效的

这里给出计算速度 的代码:

因为考虑不能让速度太快,所以给出了一个最大值

/**

* 最大速度

*/

public static final double max_speed = 8;

/**

* 通过数组里所装载的数据分析出即时速度

* 原理是:计算数组里的时间长度和增量的总数,然后求出每毫秒所走过的弧度

* 当然不能超过{@link VRecord#max_speed}

*

* @return

*/

public double getSpeed() {

if (addCount == 0) {

return 0;

}

int maxIndex = Math.min(addCount, length) - 1;

if ((record[0][1] - record[maxIndex][1]) == 0) {

return 0;

}

double detaTime = record[0][1] - record[maxIndex][1];

double sumdegree = 0;

for (int i = 0; i < length - 1; i++) {

sumdegree += record[0];

// System.out.println(record[0]);

}

// System.out.println("----------");

// System.out.println(sumdegree);

// System.out.println(detaTime);

double result = sumdegree / detaTime;

if (result > 0) {

return Math.min(result, max_speed);

} else {

return Math.max(result, -max_speed);

}

// System.out.println("v=" + result);

}

讲到这我要提一下,这个二维数组是如何做到获取最近的数据,如果超过容量,它将把原来的数据丢弃,我想直接上代码,大家就能看懂吧

/**

* 二维数组,1.保存弧度增量.2.保存产生这个增量的时间点

*/

double[][] record = new double[length][2];

/**

* 为二维数组装载数据

* 注:通过此方法,有个特点,能把最后的length组数据记录下来,length以外的会丢失

*

* @param detadegree

* @param time

*/

public void add(double detadegree, double time) {

for (int i = length - 1; i > 0; i--) {

record[0] = record[i - 1][0];

record[1] = record[i - 1][1];

}

record[0][0] = detadegree;

record[0][1] = time;

addCount++;

}

f.View惯性处理

这里的惯性处理就是用到加速度了,再用handler发消息,控制它不停减速,减到它为零为止就停止发消息

下面是handler代码

@Override

public void handleMessage(Message msg) {

double detaTime = System.currentTimeMillis() - currentTime;

switch (msg.what) {

case play: {

//如果是顺时针

if (isClockWise) {

speed = speed - a * detaTime;//减速

if (speed <= 0) {

return;

} else {

handler.sendEmptyMessageDelayed(play, delayedTime);

}

} else {

speed = speed + a * detaTime;

if (speed >= 0) {

return;

} else {

handler.sendEmptyMessageDelayed(play, delayedTime);

}

}

addDegree((float)(speed * detaTime + (a * detaTime * detaTime) / 2));//高中物理算路程S=vt+at2

// if (a < a_max) {

// a = (float)(a + a_add*detaTime);

// System.out.println("a:"+a);

// }

currentTime = System.currentTimeMillis();

invalidate();

break;

}

case stop: {

speed = 0;

handler.removeMessages(play);

}

}

super.handleMessage(msg);

}

};

android旋转动画惯性,android 之旋转罗盘 风车 开发相关推荐

  1. android旋转动画惯性,Android实现对图片放大、平移和旋转的功能

    先来看看要实现的效果图 在讲解中,需要大家提前了解一些关于图片绘制的原理的相关知识. 关于实现的流程 1.自定义View 2.获得操作图片的Bitmap 3.复写View的onTouchEvent() ...

  2. android 属性动画伸缩,Android动画开发——Animation动画效果详解

    在Android中,分别可以在xml中定义Animation,也可以在程序代码中定义. 动画类型Android的animation由四种类型组成 XML中alpha渐变透明度动画效果 scale渐变尺 ...

  3. android 圆动画效果,Android实现任意绕圆或椭圆旋转的动画——SatelliteAnimator使用介绍...

    话说实习也就快一个月了,虽然没干什么活,但是这几天总算是有一些可以写的东西. 代码中应该还存在很多问题要修改,大神们请赐教,不胜感激. 开始正题. 关于Android实现任意绕圆或椭圆旋转动画,我称之 ...

  4. android scaleanimation动画,【Android动画九章】-RotateAnimation(旋转动画)和ScaleAnimation(尺寸动画)...

    [Android动画九章]-RotateAnimation(旋转动画)和ScaleAnimation(尺寸动画) public abstract class Animation extends Obj ...

  5. android 之旋转罗盘 风车 开发 Android 随手指旋转图片

    原帖地址 源码下载地址 我要介绍的是一个 能旋转的view,说这个view能旋转有点不切实际,那是视觉效果,其实是对图片的旋转.目前它只支持图片.你可以把它认为是一个能响应手势旋转的View. 它的功 ...

  6. android 属性动画伸缩,Android的属性动画(二)加载框圆点旋转收缩放大缩小效果的实现...

    案例效果图如下, 案例实现步骤 1.首先用drawCircle()画好6个圆点 private void drawCircles(Canvas canvas) { //每个小圆之间的间隔角度 = 2π ...

  7. android组合动画还原,Android - Fragment,View动画,组合动画,属性动画

    转载请注明出处:https://blog.csdn.net/mythmayor/article/details/72876871 1.什么是Fragment 片段,碎片 * 从Android 3.0 ...

  8. android属性动画作用范围,Android开发之动画效果浅析(一)

    程序运行效果图: Android动画主要包含补间动画(Tween)View Animation.帧动画(Frame)Drawable Animation.以及属性动画Property Animatio ...

  9. android窗口动画体系,Android 7.1 GUI系统-窗口管理WMS-动画的执行(七)

    前面只是动画资源的加载过程,下面看下动画是怎么执行起来的? 前面在分析窗口申请的过程中,分析过relayoutWindow中的调用performSurfacePlacement,在这个函数的最后调用了 ...

最新文章

  1. 【Java源码分析】Vector源码分析
  2. Nature出炉「中国博士生图鉴」:过半学生想换领域换导师,40%学生受抑郁、焦虑困扰...
  3. 自信息跟信息熵的区别
  4. 大数据 智能交通调度_大数据技术在智能交通中的应用
  5. Win11系统添加新用户的方法
  6. D-News|英特尔首推融合现实,亚马逊云服务市场占比超3成
  7. Maven (1)---maven 基础知识
  8. 从Excel文件中找出在TXT文件中没有出现的 行之_代码片段
  9. Spring配置补充
  10. 【NOI2014】魔法森林
  11. Nginx 静态页面POST 请求提示405 Not Allowed
  12. J2ME-CLDC/MIDP资源
  13. C#抓取网页数据、分析并且去除HTML标签(转载)
  14. IO流实现csv文件到vcf文件生成
  15. 健身管理系统【管理员添加,删除,个人信息,项目】
  16. 【CF833D】Red-Black Cobweb(点分治)
  17. 微信个人收款码于订单应用之解决方案
  18. MySQL自定义函数实例
  19. linux下固态硬盘ssd优化
  20. 关于Rost ContentMining 6.0情感分析出现空白的解决方案

热门文章

  1. 博客迁移到GitCafe
  2. 数学分析闭区间套定理_闭区间套定理在数学教学中的一个有趣应用
  3. LibQQt系列之十《QQt 功能介绍》
  4. 诚意推荐几个腾讯、美团、阿里技术大佬的公号
  5. IE与FireFox,速度和兼容性水平相当
  6. textarea字数验证支持
  7. “东数西算”全面启动 2022中国数字经济呈现新格局
  8. oracle序时账是什么,序时账和明细账到底有什么区别
  9. 计算机仿真进去终审录的概率大吗,论文进入终审录用概率大吗
  10. Web:用 img插入图片的细节