有关oppo蝴蝶解锁的三D技术
oppo手机的界面设计也是很漂亮的。在很多界面中使用了3D技术塑造出了大量华丽的效果。在蝴蝶解锁中使用了两个对称的三D变幻,宛如蝴蝶翅膀上美丽的花纹。在受到用户点击后,随风缓慢上下扇动,充满浪漫的动感色彩。这里只在技术角度做一些探索。
这个效果由两个子view合成,每个各占整个屏幕的一半。左边子view以右边界为旋转中心,手指向右滑动距离转为绕Y轴施转的角度,角度为正。右边子view以左边界为旋转中心,手指向左滑动距离转为绕Y轴旋转的角度,角度为负,这样恰好与x轴方向一致。这种效果经过转为,可以转为像两扇门一样开关,也是很有意思的。为了保证两个view的对称性,我这里使用一张图片,沿中线分割为两个view的背景。
可以使用函数Bitmap.createBitmap实现.
左view的背景,LeftView.java:
package com.magcomm.lockscrenn; import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.view.View; class LeftView extends View {
Bitmap leftbm = null;
public int g_r = 0;
private int scr_w = 0, scr_h = 0; public void refrashView(int gr) {
g_r = gr;
invalidate();
}
public LeftView(Context context) {
super(context);
} void setBitmap(Bitmap bm) {
leftbm = bm;
scr_w = bm.getWidth() * 2;
scr_h = bm.getHeight();
} @Override
protected void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
float deg = (g_r * 1.0f / scr_w) * 180;
if (deg >= 90) {
canvas.drawBitmap(leftbm, rotateY((int) deg), null); } else if (deg > 0) {
canvas.drawBitmap(leftbm, rotateY((int) deg), null);
// lv.bringToFront();
} else {
canvas.drawBitmap(leftbm, rotateY((int) 0), null);
}
} private int centerX = 0, centerY = 0;
// 转动的总距离,跟度数比例1:1
private int deltaX = 0, deltaY = 0;
// 图片宽度高度
private int bWidth, bHeight;
// 摄像机
private Camera mCamera = new Camera();
private Matrix mMatrix = new Matrix(); Matrix rotateXY(int degreeX, int degreeY) {
deltaX = degreeX;
deltaY = degreeY;
centerX = scr_w / 2;
centerY = scr_h / 2;
mCamera.save();
mCamera.rotateY(deltaY);
mCamera.rotateX(-deltaX);
mCamera.translate(0, 0, 0);
mCamera.getMatrix(mMatrix);
mCamera.restore();
// 以图片的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
mMatrix.preTranslate(-centerX, -centerY);
mMatrix.postTranslate(centerX, centerY);
// mCamera.save(); // postInvalidate();
return mMatrix;
} Matrix rotateY(int degreeY) {
return rotateXY(0, degreeY);
} }
右View的
 代码RightView.java:
package com.magcomm.lockscrenn; import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.view.View; class RightView extends View {
Bitmap rightbm = null;
public int g_r = 0;
private int scr_w = 0, scr_h = 0; public void refrashView(int gr) {
g_r = gr;
invalidate();
}
public RightView(Context context) {
super(context);
} void setBitmap(Bitmap bm) {
rightbm = bm;
scr_w = bm.getWidth() * 2;
scr_h = bm.getHeight();
} @Override
protected void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} @Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
float deg = (g_r * 1.0f / scr_w) * 180;
if (deg <= -90) {
canvas.drawBitmap(rightbm, rotateY2((int) deg), null);
} else if (deg < 0) {
canvas.drawBitmap(rightbm, rotateY2((int) deg), null);
// rv.bringToFront(); } else {
canvas.drawBitmap(rightbm, rotateY2(0), null);
}
} // 图片的中心点坐标
private int centerX = 0, centerY = 0;
// 转动的总距离,跟度数比例1:1
private int deltaX = 0, deltaY = 0;
// 图片宽度高度
private int bWidth, bHeight;
// 摄像机
private Camera mCamera = new Camera();
private Matrix mMatrix = new Matrix(); Matrix rotateXY2(int degreeX, int degreeY) {
deltaX = degreeX;
deltaY = degreeY;
centerX = scr_w / 2;
centerY = scr_h / 2;
mCamera.save();
mCamera.rotateY(deltaY);
mCamera.rotateX(-deltaX);
mCamera.translate(scr_w / 2, 0, 0);
mCamera.getMatrix(mMatrix);
mCamera.restore();
// 以图片的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
mMatrix.preTranslate(-centerX, -centerY);
mMatrix.postTranslate(centerX, centerY);
// mCamera.save(); // postInvalidate();
return mMatrix;
} Matrix rotateY2(int degreeY) {
return rotateXY2(0, degreeY);
}
}
下面代码是两个view的动画效果,手指放开时出现缓慢的上下的有衰减的扇动效果,宛如蝴蝶颤抖的翅膀。本来自己写了一个弹簧振子的模型,通过滑动距离转化为弹簧的能量波动,进而转化为扇动的初速度,加上弹簧的阻尼运动的衰减系数,使其做带负加速度的圆周运动。但运行效果不太满意,大概需要使用JNI来实现才能满足吧,后来采取了系统自带的动画实现。
int ani_index = 0;
	private void applyRotation(float start, float end, final View v) {
		// 计算中心点
		final float centerX = scr_w / 2.0f;
		final float centerY = scr_h / 2.0f;
		final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, 0,
				0, 0, 0, 0, 0, centerX, centerY, true);
		rotation.setDuration(500);
		// rotation.setFillAfter(true);
		rotation.setRepeatCount(1);
		rotation.setRepeatMode(Animation.REVERSE);
		// rotation.setFillAfter(true);
		// rotation.setDetachWallpaper(true);
		rotation.setInterpolator(new AnticipateInterpolator());
		// 设置监听
		rotation.setAnimationListener(new Animation.AnimationListener() {
			public void onAnimationStart(Animation animation) {
			}
			// 动画结束
			public void onAnimationEnd(Animation animation) {
				// tv.post(new SwapViews());
				startAni(ani_index++);
			}
			public void onAnimationRepeat(Animation animation) {
			}
		});
		v.startAnimation(rotation);
	}
	/**
	 *
	 * AccelerateDecelerateInterpolator 在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
	 *
	 * AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
	 *
	 * AnticipateInterpolator 开始的时候向后然后向前甩
	 *
	 * AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
	 *
	 * BounceInterpolator 动画结束的时候弹起
	 *
	 * CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
	 *
	 * DecelerateInterpolator 在动画开始的地方快然后慢
	 *
	 * LinearInterpolator 以常量速率改变
	 *
	 * OvershootInterpolator 向前甩一定值后再回到原来位置
	 *
	 * @param start
	 * @param end
	 * @param v
	 * @param time
	 */
	private void applyRotation2(float start, float end, final View v, long time) {
		// 计算中心点
		final float centerX = scr_w / 2.0f;
		final float centerY = scr_h / 2.0f;
		final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, 0,
				0, 0, 0, 0, 0, centerX, centerY, true);
		rotation.setDuration(time);
		// rotation.setFillAfter(true);
		rotation.setRepeatCount(0);
		rotation.setRepeatMode(Animation.REVERSE);
		// rotation.setFillAfter(true);
		// rotation.setDetachWallpaper(true);
		rotation.setInterpolator(new LinearInterpolator());
		// 设置监听
		rotation.setAnimationListener(new Animation.AnimationListener() {
			public void onAnimationStart(Animation animation) {
			}
			// 动画结束
			public void onAnimationEnd(Animation animation) {
				// tv.post(new SwapViews());
				startAni(ani_index++);
			}
			public void onAnimationRepeat(Animation animation) {
			}
		});
		v.startAnimation(rotation);
	}
	void startAni(int index) {
		// final int ani_deg1[][] = {{60, 0}, {40, 0}, {20, 0}};
		// final int ani_deg1[][] = {{0, 60}, {0, 40}, {0, 20}};
		final int ani_deg1[][] = { { 0, 80 }, { 80, 0 }, { 0, 60 }, { 60, 0 },
				{ 0, 40 }, { 40, 0 } };
		// final int ani_deg2[][] = {{-60, 0}, {-40, 0}, {-20, 0}};
		final int ani_deg2[][] = { { 0, -80 }, { -80, 0 }, { 0, -60 },
				{ -60, 0 }, { 0, -40 }, { -40, 0 } };
		final int time[] = { 500, 500, 400, 400, 200, 200 };
		if (index > 5) {
			ani_index = 0;
		} else {
			if (u_x <= (scr_w / 2)) {
				applyRotation2(ani_deg1[index][0], ani_deg1[index][1], lv,
						time[index]);
			} else {
				applyRotation2(ani_deg2[index][0], ani_deg2[index][1], rv,
						time[index]);
			}
		}
	}
在oppo的解锁效果中,view的背面加入了对窗口buffer的特殊处理。使我们能够看到一个打开新窗口的效果,如下图:
需要添加如下函数。这里调用了系统的隐藏函数Surface.screenshot,必须使用系统签名。加入系统app中才能使用。当然,也许你也可以使用反射实现。
publicBitmap getScreenBuffer()
{
DisplaymDisplay;
DisplayMetricsmDisplayMetrics;
MatrixmDisplayMatrix = new Matrix();
WindowManagermWindowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
mDisplay= mWindowManager.getDefaultDisplay();
mDisplayMetrics= new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
mDisplay.getRealMetrics(mDisplayMetrics);
float[]dims = { mDisplayMetrics.widthPixels,
mDisplayMetrics.heightPixels};
mlock= Surface.screenshot((int) dims[0], (int) dims[1]);
returnmlock;
}
有关oppo蝴蝶解锁的三D技术的更多相关文章
- 阿里云大数据三次技术突围:Greenplum、Hadoop和“飞天”
		
阿里云大数据三次技术突围:Greenplum.Hadoop和"飞天" 对于企业来说,到底什么是云计算?相信很多企业都有这样的困惑,让我们一起回到这个原始的起点探讨究竟什么是云 ...
 - ASP.NET MVC:多语言的三种技术处理策略
		
ASP.NET MVC:多语言的三种技术处理策略 背景 本文介绍了多语言的三种技术处理策略,每种策略对应一种场景,这三种场景是: 多语言资源信息只被.NET使用. 多语言资源信息只被Javascrip ...
 - 谈谈在DevOps实践中,感觉最重要的这三个技术……
		
从国内众多DevOps实践中,我们能看到下面三个技术尤其重要和火热: 容器:容器从根本上解决了软件对环境的依懒性,解决了各个环境之间的差异问题:它可以加速部署的速度,提高部署的效率:降低部署的成本.容 ...
 - 【转载】目前主流过滤XSS的三种技术
		
目前主流过滤XSS的三种技术 过滤 过滤,顾名思义,就是将提交上来的数据中的敏感词汇直接过滤掉.例如对"<script>"."<a>". ...
 - Java 基础入门随笔(1) JavaSE版——java语言三种技术架构
		
1.java语言的三种技术架构: J2SE(java 2 Platform Standard Edition):标准版,是为开发普通桌面和商务应用程序提供的解决方案.该技术体系是其他两者的基础,可以完 ...
 - ASP、JSP、PHP 三种技术比较
		
目前,最常用的三种动态网页语言有ASP(Active Server Pages),JSP(JavaServer Pages),PHP (Hypertext Preprocessor). 简 介 : A ...
 - Oracle用户解锁的三种办法及默认的用户与密码
		
ORA-28000: the account is locked-的解决办法 2009-11-11 18:51 ORA-28000: the account is locked 第1步:使用PL/SQ ...
 - Docker数据卷Volume实现文件共享、数据迁移备份(三)--技术流ken
		
前言 前面已经写了两篇关于docker的博文了,在工作中有关docker的基本操作已经基本讲解完了.相信现在大家已经能够熟练配置docker以及使用docker来创建镜像以及容器了.本篇博客将会讲解如 ...
 - [华三] IPv6技术白皮书(V1.00)
		
IPv6技术白皮书(V1.00) http://www.h3c.com/cn/d_200802/605649_30003_0.htm H3C S7500E IPv6技术白皮书 关键词:IPv6,隧道 ...
 
随机推荐
- iOS系统原生二维码条形码扫描
			
本文讲述如何用系统自带的东东实现二维码扫描的功能:点击当前页面的某个按钮,创建扫描VIEW.细心的小伙伴可以发现 title被改变了,返回按钮被隐藏了.这个代码自己写就行了,与本文关系不大...绿色的 ...
 - MVC中AuthorizeAttribute用法并实现权限控制
			
1.创建一个类(用来检查用户是否登录和用户权限)代码如下: public class AuthorizeFilterAttribute: AuthorizeAttribute { //Autho ...
 - BZOJ 1202: [HNOI2005]狡猾的商人( 差分约束 )
			
好像很多人用并查集写的... 前缀和, 则 sumt - sums-1 = v, 拆成2条 : sumt ≤ sums-1 + v, sums-1 ≤ sumt - v 就是一个差分约束, 建图跑SP ...
 - BZOJ 3907: 网格( 组合数 + 高精度 )
			
(0,0)->(n,m)方案数为C(n,n+m), 然后减去不合法的方案. 作(n,m)关于y=x+1的对称点(m-1,n+1), 则(0,0)->(m-1,n+1)的任意一条路径都对应( ...
 - CSS小技巧-图片自动缩放
			
css的一个重要属性:max-width min-width 示例: <div width="500" height="259"><p> ...
 - judge loop in undirected graph
			
一 深度优先遍历,参考前面DFS(white and gray and black) 二 根据定点以及边数目进行判断 如果m(edge)大于n(vertex),那么肯定存在环 算法如下: 1 删除所有 ...
 - 我的Python成长之路---第七天---Python基础(21)---2016年2月27日(晴)
			
四.面向对象进阶 1.类方法 普通的方法通过对象调用,至少有一个self参数(调用的时候系统自动传递,不需要手工传递),而类方法由类直接调用,至少有一个cls参数,执行时,自动将调用该方法的类赋值个c ...
 - 引入工程报包导入异常:import javax.servlet.annotation.WebFilter;
			
引入工程报包导入异常:import javax.servlet.annotation.WebFilter; (2013-02-21 16:38:00) 分类: java 今天上午导入了一个项目,用 ...
 - CMarkUp接口说明
			
CMarkup是一个小型XML的分析器,实现语言是C++,英文版的接口说明地址为:http://www.firstobject.com/dn_markupmethods.htm 有厉害的网友已经翻译出 ...
 - Android访问网络
			
Android中访问网络用的是HttpClient的方式,即Apache提供的一个jar包.安卓中继承了改jar包,所以安卓adt中不需要专门import该jar,直接就可以使用. 以下是MainAc ...