android 解锁绘制,Android图形解锁的绘制

Android图形解锁的绘制

发布时间:2020-07-17 00:50:56

来源:51CTO

阅读:590

作者:NashLegend

先上图:

2b6ead99e1d24f9202859b836970a2a2.png

其实很简单,不用过多解释,一点点注释就够了。

Java代码:package com.example.graphicunlock;

import android.os.Bundle;

import android.os.Handler;

import android.app.Activity;

import android.content.Context;

import android.content.pm.ActivityInfo;

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Bitmap.Config;

import android.graphics.Paint.Style;

import android.graphics.Path;

import android.graphics.PointF;

import android.graphics.PorterDuff.Mode;

import android.graphics.PorterDuffXfermode;

import android.util.DisplayMetrics;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnTouchListener;

import android.view.ViewGroup.LayoutParams;

import android.view.Window;

import android.view.WindowManager;

import android.widget.ImageView;

import android.widget.RelativeLayout;

public class MainActivity extends Activity implements OnTouchListener {

private RelativeLayout relativeLayout;// 用来摆放九个圆形

private ImageView view;// 用来绘制解锁路径

private Path path;// 划过的路径

private Paint paint;

private Canvas canvas;

private Dot[] array = new Dot[9];// 圆形的数组

private Dot lastDot;// 上一个经过的点

private Bitmap bitmap;// 绘制用的bitmap

private boolean drawing = false;// 是否正在画图

private int radius = 0;// 圆形半径

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// 锁定竖屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

// 不显示标题栏

requestWindowFeature(Window.FEATURE_NO_TITLE);

// 全屏

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(R.layout.activity_main);

relativeLayout = (RelativeLayout) findViewById(R.id.rela);

view = (ImageView) findViewById(R.id.view);

view.setOnTouchListener(this);

drawDots();

}

/**

* 放置九个圆形 将九个圆形在屏幕中居中放置,每屏幕的三分之一宽度为一格,横竖排各三个,每个圆宽度是屏幕宽度的1/6

*/

protected void drawDots() {

int TopMars = (getScreenHeight() - getScreenWidth()) / 2;

radius = getScreenWidth() / 12;

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(

radius * 2, radius * 2);

params.leftMargin = (int) (radius * 4 * (j + 0.25));

params.topMargin = (int) (TopMars + radius * 4 * (i + 0.25));

// 新建半径为radius的圆形

Dot dot = new Dot(this, radius);

array[i * 3 + j] = dot;

relativeLayout.addView(dot, params);

}

}

}

/**

* 检查pointF是否在某个圆形范围内

*

* @param point

* 要检查的点

* @return 如果确实在某个圆形范围内,则返回该圆形,反之返回null

*/

private Dot hitValidDot(PointF point) {

for (int i = 0; i < array.length; i++) {

Dot dot = array[i];

if (!dot.getPassed()) {

int[] location = { 0, 0 };

dot.getLocationOnScreen(location);

if (Math.sqrt((point.x - location[0] - radius)

* (point.x - location[0] - radius)

+ (point.y - location[1] - radius)

* (point.y - location[1] - radius)) < radius) {

return dot;

}

}

}

return null;

}

/**

* 要绘制到的目标图片上的触摸事件 本方法里view.invalidate()并不是必须的,有没有一样……

*/

@Override

public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

// 检查手机按下的点是否在某个圆形内,如果是则以此圆形为起点开始绘制图形

PointF point = new PointF(event.getRawX(), event.getRawY());

Dot dot = hitValidDot(point);

if (dot != null) {

// 开始绘制 先实例化要绘制的bitmap canvas paint 和绘制的路径path

bitmap = Bitmap.createBitmap(getWindowWidth(),

getWindowHeight(), Config.ARGB_8888);

canvas = new Canvas(bitmap);

paint = new Paint();

path = new Path();

// 获取此圆形中心点的位置

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) dot

.getLayoutParams();

PointF startPoint = new PointF(params.leftMargin + radius,

params.topMargin + radius);

// 将loasDot赋值给dot,并将dot设置为经过状态

lastDot = dot;

lastDot.drawPassed();

// 将圆形的中心点设置为路径的起点 并设置要绘制路径的颜色的宽度

path.moveTo(startPoint.x, startPoint.y);

paint.setARGB(255, 0, 0, 255);

paint.setStrokeWidth(8);

paint.setStyle(Style.STROKE);

// 绘制到屏幕

view.setImageBitmap(bitmap);

// 标记为正在绘图中

drawing = true;

}

break;

case MotionEvent.ACTION_MOVE:

if (drawing) {

// 先清空图片 否则看到的是每次绘制的叠加效果

clear();

// 同MotionEvent.ACTION_DOWN中一样 检查是否经过了某一点

PointF point2 = new PointF(event.getRawX(), event.getRawY());

Dot dot2 = hitValidDot(point2);

if (dot2 != null) {

// 不过有时候两点之间可能会有第三个点,如果第三个点为非经过状态,则将此点设置为经过状态

Dot dotBetween = checkDotBetween(lastDot, dot2);

if (dotBetween != null) {

lastDot = dotBetween;

lastDot.drawPassed();

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) dot2

.getLayoutParams();

path.lineTo(params.leftMargin + radius,

params.topMargin + radius);

}

lastDot = dot2;

lastDot.drawPassed();

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) dot2

.getLayoutParams();

path.lineTo(params.leftMargin + radius, params.topMargin

+ radius);

}

// 绘制出经过的所有点的路径

canvas.drawPath(path, paint);

// 绘制出上一个点到手指触摸的位置的路径

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) lastDot

.getLayoutParams();

canvas.drawLine(params.leftMargin + radius, params.topMargin

+ radius, event.getX(), event.getY(), paint);

view.invalidate();

}

break;

case MotionEvent.ACTION_UP:

if (drawing) {

// 手指抬起后,清空并重新绘制所有经过的点的路径,这样就会清除上一个点到手指触摸的位置的路径了

clear();

canvas.drawPath(path, paint);

view.invalidate();

// 绘制完毕,将绘制状态改为false

drawing = false;

// 三秒种后重置,放在这仅仅是为了测试重置功能

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

clearAllDrawing();

}

}, 3000);

}

break;

default:

break;

}

return true;

}

/**

* 重置所有为初始状态

*/

protected void clearAllDrawing() {

clear();

for (int i = 0; i < array.length; i++) {

Dot dot = array[i];

if (dot != null) {

dot.drawNormal();

}

}

drawing = false;

}

/**

* 查检两点之间是否经过第三点,如果是则返回第三点,否则返回null

*/

protected Dot checkDotBetween(Dot dot1, Dot dot2) {

int[] loc1 = { 0, 0 };

int[] loc2 = { 0, 0 };

dot1.getLocationOnScreen(loc1);

dot2.getLocationOnScreen(loc2);

// 两点之间的中点

PointF pointF = new PointF((loc1[0] + loc2[0]) / 2 + radius,

(loc1[1] + loc2[1]) / 2 + radius);

return hitValidDot(pointF);

}

/**

* 清空画面

*/

protected void clear() {

if (canvas != null && paint != null) {

paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));

canvas.drawPaint(paint);

paint.setXfermode(new PorterDuffXfermode(Mode.SRC));

view.invalidate();

}

}

/**

* @return 屏幕宽度

*/

public int getScreenWidth() {

DisplayMetrics metrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metrics);

return metrics.widthPixels;

}

/**

* @return 屏幕高度

*/

public int getScreenHeight() {

DisplayMetrics metrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metrics);

return metrics.heightPixels;

}

/**

* @return 返回窗口内容的宽度,不包括通知栏的标题栏,其实跟getScreenWidth()一样

*/

public int getWindowWidth() {

return getWindow().findViewById(Window.ID_ANDROID_CONTENT).getWidth();

}

/**

* @return 返回窗口内容的高度,不包括通知栏的标题栏,但是在这里是全屏,所以与getScreenHeight()返回的其实是一致的

*/

public int getWindowHeight() {

return getWindow().findViewById(Window.ID_ANDROID_CONTENT).getHeight();

}

/**

* 圆形

*/

public class Dot extends ImageView {

private int dotradius = 0;// 圆形半径

private boolean passed = false;// 是否经过的状态

public Dot(Context context) {

super(context);

}

public Dot(Context context, int rad) {

super(context);

dotradius = rad;

setLayoutParams(new LayoutParams(dotradius * 2, dotradius * 2));

drawNormal();

}

/**

* 绘制未经过时的状态

*/

public void drawNormal() {

passed = false;

Bitmap bm = Bitmap.createBitmap(dotradius * 2, dotradius * 2,

Config.ARGB_8888);

Paint paint = new Paint();

Canvas canvas = new Canvas(bm);

paint.setAntiAlias(true);

paint.setARGB(255, 156, 156, 156);

paint.setStyle(Style.STROKE);

paint.setStrokeWidth(5);

canvas.drawCircle(dotradius, dotradius,

dotradius - paint.getStrokeWidth(), paint);

paint.setStrokeWidth(1);

paint.setStyle(Style.FILL_AND_STROKE);

canvas.drawCircle(dotradius, dotradius, 3, paint);

setImageBitmap(bm);

}

/**

* 绘制经过时的状态

*/

public void drawPassed() {

passed = true;

Bitmap bm = Bitmap.createBitmap(dotradius * 2, dotradius * 2,

Config.ARGB_8888);

Paint paint = new Paint();

Canvas canvas = new Canvas(bm);

paint.setAntiAlias(true);

paint.setARGB(255, 0, 0, 255);

paint.setStyle(Style.STROKE);

paint.setStrokeWidth(5);

canvas.drawCircle(dotradius, dotradius,

dotradius - paint.getStrokeWidth(), paint);

paint.setStyle(Style.FILL_AND_STROKE);

canvas.drawCircle(dotradius, dotradius, dotradius / 3, paint);

setImageBitmap(bm);

}

public boolean getPassed() {

return passed;

}

}

}

布局xml代码,很简单:

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity" >

android:id="@+id/rela"

android:layout_width="match_parent"

android:layout_height="match_parent" />

android:id="@+id/view"

android:layout_width="match_parent"

android:layout_height="match_parent" />

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值