Android中如何给腾讯视频播放器Android加锁-简书

android开发之简单视频播放器(VideoView) - 简书
android开发之简单视频播放器(VideoView)
简单视频播放器的使用
一、简单使用videoView和MediaController实现播放控制
1、添加需要的权限
&uses-permission android:name="android.permission.INTERNET"/&
&uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/&
2、设置布局
&VideoView
android:id="@+id/main_video"
android:layout_width="match_parent"
android:layout_height="240dp"
3、实例化VideoView
videoView = (VideoView) findViewById(R.id.main_video);
MediaController
controller = new MediaController(this);//实例化控制器
String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"jiaoxue.mp4";
* 本地播放
videoView.setVideoPath("path");
* 网络播放
videoView.setVideoURI(Uri.parse("http://192.168.1.109:8080/video/jiaoxue.mp4"));
* 将控制器和播放器进行互相关联
controller.setMediaPlayer(videoView);
videoView.setMediaController(controller);
二、自定义播放器 (贴上源码)
&?xml version="1.0" encoding="utf-8"?&
&RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.zzj.myeasyvideoplaydemo.MainActivity"&
&RelativeLayout
android:layout_width="match_parent"
android:layout_height="240dp"&
&VideoView
android:id="@+id/main_video"
android:layout_width="match_parent"
android:layout_height="240dp"
&LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_marginLeft="-20dp"
android:layout_marginRight="-20dp"
android:max="100"
android:indeterminate="false"
android:progress="20"
&RelativeLayout
android:gravity="center_vertical"
android:background="#101010"
android:layout_width="match_parent"
android:layout_height="match_parent"&
&LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
&ImageView
android:id="@+id/play_pasue_image"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/video_play_blue"
android:id="@+id/main_current_time"
android:layout_marginLeft="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:textSize="14dp"
android:textColor="#ffffff"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"
android:textSize="14dp"
android:textColor="#4c4c4c"
android:id="@+id/main_totally_time"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:textSize="14dp"
android:textColor="#ffffff"
&/LinearLayout&
&LinearLayout
android:layout_marginRight="5dp"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"&
&ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/video_sound_switch"
android:layout_width="100dp"
android:layout_height="5dp"
android:progress="20"
android:max="100"
&ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/play"
&/LinearLayout&
&/RelativeLayout&
&/LinearLayout&
&/RelativeLayout&
&/RelativeLayout&
视频Java类:
public class TestMovieActivity extends BaseActivity {
public static final int UPDATA_VIDEO_NUM = 1;
private CustomVideoView videoV
private MediaC//控制器
private RelativeLayout videoL
private LinearLayout controllerL//播放器的总控制布局
private SeekBar play_seek, volume_//播放进度和音量控制进度
private ImageView play_controller_image, screen_image,volume_I
private TextView current_time_tv, totally_time_
private int screen_width, screen_
private AudioManager audioM//音量控制器
private boolean screen_flag =//判断屏幕转向
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实例化音量控制器
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
setContentView(R.layout.act_testmovie);
initView();
initData();
initViewOnClick();
controller = new MediaController(this);//实例化控制器
path = Environment.getExternalStorageDirectory().getAbsolutePath()+"jiaoxue.mp4";
* 本地播放
videoView.setVideoPath("");
* 网络播放
videoView.setVideoURI(Uri.parse("http://192.168.1.109:8080/video/jiaoxue.mp4"));
//视频播放时开始刷新
videoView.start();
play_controller_image.setImageResource(R.mipmap.video_play_blue);
handler.sendEmptyMessage(UPDATA_VIDEO_NUM);
* 将控制器和播放器进行互相关联
controller.setMediaPlayer(videoView);
videoView.setMediaController(controller);
protected void onPause() {
super.onPause();
handler.removeMessages(UPDATA_VIDEO_NUM);
protected void onDestroy() {
super.onDestroy();
handler.removeMessages(UPDATA_VIDEO_NUM);
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 判断当前屏幕的横竖屏状态
int screenOritentation = getResources().getConfiguration().
if (screenOritentation == Configuration.ORIENTATION_LANDSCAPE) {
//横屏时处理
setVideoScreenSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
volume_seek.setVisibility(View.VISIBLE);
volume_Image.setVisibility(View.VISIBLE);
screen_flag =
//清除全屏标记,重新添加
getWindow().clearFlags((WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN));
getWindow().addFlags((WindowManager.LayoutParams.FLAG_FULLSCREEN));
//竖屏时处理
setVideoScreenSize(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dp2px(mContext,240));
screen_flag =
volume_seek.setVisibility(View.GONE);
volume_Image.setVisibility(View.GONE);
//清除全屏标记,重新添加
getWindow().clearFlags((WindowManager.LayoutParams.FLAG_FULLSCREEN));
getWindow().addFlags((WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN));
* 通过handler对播放进度和时间进行更新
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == UPDATA_VIDEO_NUM) {
//获取视频播放的当前时间
int currentTime = videoView.getCurrentPosition();
//获取视频的总时间
int totally = videoView.getDuration();
//格式化显示时间
updataTimeFormat(totally_time_tv, totally);
updataTimeFormat(current_time_tv, currentTime);
//设置播放进度
play_seek.setMax(totally);
play_seek.setProgress(currentTime);
//自己通知自己更新
handler.sendEmptyMessageDelayed(UPDATA_VIDEO_NUM, 500);//500毫秒刷新
* 设置横竖屏时的视频大小
* @param width
* @param height
private void setVideoScreenSize(int width, int height) {
//获取视频控件的布局参数
ViewGroup.LayoutParams videoViewLayoutParams = videoView.getLayoutParams();
//设置视频范围
videoViewLayoutParams.width =
videoViewLayoutParams.height =
videoView.setLayoutParams(videoViewLayoutParams);
//设置视频和控制组件的layout
ViewGroup.LayoutParams videoLayoutLayoutParams= videoLayout.getLayoutParams();
videoLayoutLayoutParams.width =
videoLayoutLayoutParams.height =
videoLayout.setLayoutParams(videoLayoutLayoutParams);
* 时间格式化
* @param textView
* @param millisecond 总时间 毫秒
private void updataTimeFormat(TextView textView, int millisecond) {
//将毫秒转换为秒
int second = millisecond / 1000;
//计算小时
int hh = second / 3600;
//计算分钟
int mm = second % 3600 / 60;
int ss = second % 60;
//判断时间单位的位数
String str =
if (hh != 0) {//表示时间单位为三位
str = String.format("%02d:%02d:%02d", hh, mm, ss);
str = String.format("%02d:%02d", mm, ss);
//将时间赋值给控件
textView.setText(str);
* 按钮点击事件
private void initViewOnClick() {
//播放按钮事件
play_controller_image.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//判断播放按钮的状态
if (videoView.isPlaying()) {
play_controller_image.setImageResource(R.mipmap.video_play_blue);
//视频暂停
videoView.pause();
//当视频处于暂停状态,停止handler的刷新
handler.removeMessages(UPDATA_VIDEO_NUM);
play_controller_image.setImageResource(R.mipmap.video_pause_white);
videoView.start();
//当视频播放时,通知刷新
handler.sendEmptyMessage(UPDATA_VIDEO_NUM);
//播放进度条事件
play_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//设置当前的播放时间
updataTimeFormat(current_time_tv, progress);
if (videoView.getDuration() == progress) {
play_controller_image.setImageResource(R.mipmap.video_play_blue);
public void onStartTrackingTouch(SeekBar seekBar) {
//拖动视频进度时,停止刷新
handler.removeMessages(UPDATA_VIDEO_NUM);
public void onStopTrackingTouch(SeekBar seekBar) {
//停止拖动后,获取总进度
int totall = seekBar.getProgress();
//设置VideoView的播放进度
videoView.seekTo(totall);
//重新handler刷新
handler.sendEmptyMessage(UPDATA_VIDEO_NUM);
//音量控制条事件
volume_seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//设置音量变动后系统的值
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,progress,0);
public void onStartTrackingTouch(SeekBar seekBar) {
public void onStopTrackingTouch(SeekBar seekBar) {
//设置全屏按钮点击事件
screen_image.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showLog("------当前屏幕标记----:"+screen_flag);
if(screen_flag){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//控制屏幕竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//控制屏幕横屏
protected void initView() {
videoView = (CustomVideoView) findViewById(R.id.main_video);
videoLayout = (RelativeLayout) findViewById(R.id.act_testmovie_videolayout);
controllerLayout = (LinearLayout) findViewById(R.id.main_controller_liner);
play_seek = (SeekBar) findViewById(R.id.main_play_seek);
volume_seek = (SeekBar) findViewById(R.id.main_volume_seek);
current_time_tv = (TextView) findViewById(R.id.main_current_time);
totally_time_tv = (TextView) findViewById(R.id.main_totally_time);
play_controller_image = (ImageView) findViewById(R.id.play_pasue_image);
screen_image = (ImageView) findViewById(R.id.main_screen_image);
volume_Image = (ImageView) findViewById(R.id.act_testmovies_volume_image);
DisplayMetrics metric = new DisplayMetrics();
screen_width = metric.widthP
screen_height = metric.heightP
protected void initData() {
//获取设置音量的最大值
int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
volume_seek.setMax(volumeMax);
//获取设置当前音量
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
volume_seek.setProgress(currentVolume);
补上CustomVideoView
public class CustomVideoView extends VideoView {
//声明屏幕的大小
int width = 1920;
int height = 1080;
public CustomVideoView(Context context) {
super(context);
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
public CustomVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//设置宽高
int defaultWidth = getDefaultSize(width,widthMeasureSpec);
int defaultHeight = getDefaultSize(height,heightMeasureSpec);
setMeasuredDimension(defaultWidth,defaultHeight);
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
用到的组件1、通过CocoaPods安装项目名称项目信息AFNetworking网络请求组件FMDB本地数据库组件SDWebImage多个缩略图缓存组件UICKeyChainStore存放用户账号密码组件Reachability监测网络状态DateTools友好化时间MBP...
视频播放器在App是很常见的,有哪些视频播放器呢?具体情况该用哪款呢?这里我总结了常用的视屏播放Videoview、mediaplayer+surfaceview、vitamio、jcplayer的使用方法并写了各自的播放示例。 代码在这里面项目目录: 用到的视频地址: A...
目录介绍 1.关于此视频封装库介绍 1.1 能够满足那些业务需求 1.2 对比同类型的库有哪些优势 2.关于使用方法说明 2.1 关于gradle引用说明 2.2 添加布局 2.3 最简单的视频播放器参数设定 2.4 注意的问题 2.5 关于开源库中的类说明 3.关于播放类...
父母在,人生尚有来处。父母去,人生只剩归途。 原本只是脑子一热想要百度一下「父母在,不远游,游必有方」的由来,却没想到被上面这段话触动到眼眶发红。 我向来是个很恋家的人,虽然在年少轻狂不甚懂事的时候也曾与父母拌嘴吵架闹意见,但对家的依恋却更像是一种与生俱来的本能。 如今,即...
一些肢体语言会泄露你内心的想法,即使这个想法你并不知道,这些,你都知道吗?据现在的科学研究来看,人们所知道的肢体语言也只有70-80%的正确率。 作者对肢体语言很感兴趣的起源在书上并没有说,但是他和我们分享了这样一件事,有一年他得了咽喉类的疾病,有好几天不能说话,所以天天在...
什么状态 我也不知道 醒的时候很难睡着 熬夜熬的烦躁 每天躺在床上但都觉得好累好累 睡的时候 戴上眼罩 想着想着事情就开始流泪 莫名其妙哽咽 眼睛又干又痒 每天不论吃没吃东西 肚子都在叫叫叫 有圈子 有原来喜欢呆的地方 但都不想再去了 只想静静 一个人 改变一点事情
昨晚朋友生日,家庭聚餐。餐后都约着去寿星家继续娱乐。
我们几个脾气相投的中年少女,凑在寿星婆的闺房拉呱。一个姐姐说:“以前总觉得你很清高,不好接近,没想到能跟我们一起这样吃喝玩乐,还教我练瑜伽。”
原来,想象中的我跟现实中的我,还有旁人眼中的我,是如此不同。
今天9点起床,9.30分出发到公司。和公司老总及总厨去考察菜品配送公司,先谈了一家无果,然而他介绍了一家,这家还算符合要求的,在等待对方报价中。中午考察了蜀九香火锅,进行了了解,研究为什么生意好,下午跟老板汇报了工作,晚上在店里研究了底料,要坚信自己的东西好,坚持自己的路,...快给你的app上锁吧(android图案解锁) - 简书
快给你的app上锁吧(android图案解锁)
序言:前两天因为项目的原因,去做了一下仿ios的数字解锁功能,然后写了那篇,后来想到应用中常见的还有另外一种解锁就是绘制图案解锁,这两种解锁的布局看起来是很相似的,而且产生的结果也很相似,但是用户的操作不一样,下面我就给大家来说明一下
话不多说,先上图:
抬起错误状态
抬起错误状态
抬起正确状态
抬起正确状态
这里又是一个九宫格布局,布局可以参考上一篇,只不过这里的九宫格上我们画的是图片(bitmap)。onDraw方法中我们需要画两个东西,一个是点,另一个是线,画点我们就不多说了,根据坐标,将圆形图片画上去即可;
下面我们来看画线:
1、首先先要获得按下点的集合:
我们可以用集合来保存touch事件中按下的时候是九宫格中的点
2、然后每两个点连成一条线
首先需要判断第一个点的状态是否是正常的(这个是点的属性,可以自定义),正常的话两点之间就连正确的线,错误的话两点之间就连错误的线
布局画好之后我们还需要判断手势,即onTouch事件,按下,移动,抬起。
(1). 清空之前的操作,新一轮的绘制图案开始
(2). 检查当前按下的点与九宫格中的点是否吻合,如果吻合,将判断第一次是否选中九宫格中的点这个标识位置为true
(1). 判断第一次按下是否选中九宫格中的点
(2). 如果第一次选中九宫格中的点,将手指在移动且手指按下的点不是九宫格中的点这个标识位置为true
(1). 将所有的标识位都还原成初始化
绘制结束:
1、先判断绘制成不成立
2、然后根据绘制的结果向界面发送回调
至此,相关分析就结束了,详细的释义我会在代码中给出:
public class GraphicLockView extends View {
private Point[][] points = new Point[3][3];
//创建一个3行3列的点数组
private boolean isI
//判断有没有初始化
private boolean isS
//判断手指第一次按下屏幕有没有选中点
private boolean isFinishM
//表示一次完整的图案绘制是否结束
private boolean isMoveButNotP
//表示手指在移动,但是并不是九宫格中的点
private float width,
//屏幕宽高
private static final int MIN_POINT = 4;
//最小能构成密码的点数
private float offsetsX, offsetsY; //偏移量(在这里偏移量等于大边减去小边再除以2)
private float bitmapR;
//图片资源的半径
private float moveX, moveY;
//手势移动的x,y坐标
private Bitmap bpPointNormal, bpPointPressed, bpPointE
//点的三种图片
private Bitmap bpLinePressed, bpLineE
//线的三种图片
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private List&Point& selectPointList = new ArrayList&&();
//储存按下的点的集合
private Matrix matrix = new Matrix();
//矩阵,用来处理线的缩放
private OnGraphicLockListener onGraphicLockL
//对外的监听器
public GraphicLockView(Context context) {
super(context);
public GraphicLockView(Context context, AttributeSet attrs) {
super(context, attrs);
public GraphicLockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
public void setOnGraphicLockListener(OnGraphicLockListener onGraphicLockListener) {
this.onGraphicLockListener = onGraphicLockL
protected void onDraw(Canvas canvas) {
//绘制之前要先初始化一下点,所以要先判断有没有初始化过
if (!isInit) {
//初始化点
initPoints();
//绘制——将点绘制到画布上
pointToCanvas(canvas);
if (selectPointList.size() & 0) {
Point startPoint = selectPointList.get(0);
//绘制九宫格坐标里的点
for (int i = 0; i & selectPointList.size(); i++) {
Point endPoint = selectPointList.get(i);
lineToCanvas(canvas, startPoint, endPoint);
startPoint = endP
//绘制九宫格坐标以外的点
if (isMoveButNotPoint) {
lineToCanvas(canvas, startPoint, new Point(moveX, moveY));
* 初始化点
private void initPoints() {
//1、先拿到画布的宽高(屏幕的宽高)
width = getWidth();
height = getHeight();
/*================================================================================*/
//2、判断横竖屏并且计算偏移量
if (width & height) {
//横屏时只有x坐标有偏移量
offsetsX = (width - height) / 2;
* 将手机屏幕可以看作是一个正方形(因为九宫格是正方形,在这里比较好计算),以最小边为基准
//竖屏时只有y坐标有偏移量
offsetsY = (height - width) / 2;
/*================================================================================*/
//3、图片资源(图片资源自己加上)
bpPointNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
bpPointPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
bpPointError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);
bpLinePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
bpLineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
/*================================================================================*/
//4、点的坐标
points[0][0] = new Point(offsetsX + width / 4, offsetsY + height / 4);
points[0][1] = new Point(offsetsX + width / 2, offsetsY + height / 4);
points[0][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 4);
points[1][0] = new Point(offsetsX + width / 4, offsetsY + height / 2);
points[1][1] = new Point(offsetsX + width / 2, offsetsY + height / 2);
points[1][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 2);
points[2][0] = new Point(offsetsX + width / 4, offsetsY + height - height / 4);
points[2][1] = new Point(offsetsX + width / 2, offsetsY + height - height / 4);
points[2][2] = new Point(offsetsX + width - width / 4, offsetsY + height - height / 4);
/*================================================================================*/
//5、计算图片资源的半径
bitmapR = bpPointNormal.getWidth() / 2;
/*================================================================================*/
//6、设置密码按键,初始化每个点,设置为1——9
int index = 1;
for (int i = 0; i & points. i++) {
for (int j = 0; j & points[i]. j++) {
points[i][j].index =
/*================================================================================*/
//初始化完成
public boolean onTouchEvent(MotionEvent event) {
moveX = event.getX();
moveY = event.getY();
isFinishMove =
isMoveButNotPoint =
Point point =
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//每次手指按下的时候都表示重新绘制图案
resetPoint();
//1、检查当前按下的点与九宫格中的九个点是否吻合
point = checkSelectPoint();
if (point != null) {
isSelect =
case MotionEvent.ACTION_MOVE:
if (isSelect) {
point = checkSelectPoint();
if (point == null) {
isMoveButNotPoint =
case MotionEvent.ACTION_UP:
isFinishMove =
isSelect =
//选中重复检查
if (!isFinishMove && isSelect && point != null) {
if (checkCrossPoint(point)) {
isMoveButNotPoint =
//非交叉点(新的点)
point.status = Point.STATE_PRESSED;
selectPointList.add(point);
//绘制结束
if (isFinishMove) {
//绘制不成立
if (selectPointList.size() == 1) {
resetPoint();
//绘制错误,点不够
} else if (selectPointList.size() & MIN_POINT && selectPointList.size() & 0) {
if (null != onGraphicLockListener) {
onGraphicLockListener.setPwdFailure();
errorPoint();
//绘制成功
if (null != onGraphicLockListener) {
String strPassword = "";
for (Point pwdPoint : selectPointList) {
strPassword += pwdPoint.
if (!TextUtils.isEmpty(strPassword)) {
onGraphicLockListener.setPwdSuccess(strPassword);
correctPoint();
//刷新view,会调用onDraw方法
postInvalidate();
* 检查交叉点
* @param point 点
* @return 是否交叉
private boolean checkCrossPoint(Point point) {
if (selectPointList.contains(point)) {
* 设置绘制不成立
public void resetPoint() {
//将点的状态还原
for (Point point : selectPointList) {
point.status = Point.STATE_NORMAL;
selectPointList.clear();
* 设置绘制错误,将点的状态还原
public void errorPoint() {
for (Point point : selectPointList) {
point.status = Point.STATE_ERROR;
new Thread(new Runnable() {
public void run() {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
handler.sendEmptyMessage(0);
}).start();
* 设置绘制成功,将点的状态还原
private void correctPoint() {
new Thread(new Runnable() {
public void run() {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
handler.sendEmptyMessage(0);
}).start();
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
for (Point point : selectPointList) {
point.status = Point.STATE_NORMAL;
selectPointList.clear();
postInvalidate();
private Point checkSelectPoint() {
for (int i = 0; i & points. i++) {
for (int j = 0; j & points[i]. j++) {
Point point = points[i][j];
if (AppUtil.isCoincide(point.x, point.y, bitmapR, moveX, moveY)) {
* 将点绘制到画布上
* @param canvas 画布
private void pointToCanvas(Canvas canvas) {
//遍历点的集合
for (int i = 0; i & points. i++) {
for (int j = 0; j & points[i]. j++) {
Point point = points[i][j];
if (points[i][j].status == Point.STATE_PRESSED) {
canvas.drawBitmap(bpPointPressed, point.x - bitmapR, point.y - bitmapR, mPaint);
} else if (points[i][j].status == Point.STATE_ERROR) {
canvas.drawBitmap(bpPointError, point.x - bitmapR, point.y - bitmapR, mPaint);
canvas.drawBitmap(bpPointNormal, point.x - bitmapR, point.y - bitmapR, mPaint);
* 将线绘制到画布上
* @param canvas
* @param startPoint 开始的点
* @param endPoint
private void lineToCanvas(Canvas canvas, Point startPoint, Point endPoint) {
float lineLength = (float) AppUtil.twoPointDistance(startPoint, endPoint);
float degree = AppUtil.getDegrees(startPoint, endPoint);
canvas.rotate(degree, startPoint.x, startPoint.y);
if (startPoint.status == Point.STATE_PRESSED) {
//按下的状态
//设置线的缩放比例,在这里线是往一个方向缩放的,即x轴,我们只需要设置x轴的缩放比例即可,y轴默认为1
matrix.setScale(lineLength / bpLinePressed.getWidth(), 1);
matrix.postTranslate(startPoint.x - bpLinePressed.getWidth() / 2, startPoint.y - bpLinePressed.getHeight() / 2);
canvas.drawBitmap(bpLinePressed, matrix, mPaint);
//错误的状态
matrix.setScale(lineLength / bpLineError.getWidth(), 1);
matrix.postTranslate(startPoint.x - bpLineError.getWidth() / 2, startPoint.y - bpLineError.getHeight() / 2);
canvas.drawBitmap(bpLineError, matrix, mPaint);
canvas.rotate(-degree, startPoint.x, startPoint.y);
//把旋转的角度转回来
* 图案监听器
public interface OnGraphicLockListener {
void setPwdSuccess(String password);
void setPwdFailure();
来看一波gif动图:
Github下载地址:
公众号:Android技术经验分享
Android实习&&经验交流群:
掘金:https://juejin.im/user/ff4b006b0f45f3
CSDN:http://blog.csdn.net/lovecyg123/
GitHub:https://github.com/Jakemesdg/
微信公众号:Android先生
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新ViewPager图表(Chart)菜单(Menu)浮动菜单对话框空白页滑动删除手势操作RecyclerViewCardColorDrawableSpinner...
原文链接:https://github.com/opendigg/awesome-github-android-ui 在 Github 上做了一个很新的 Android 开发相关开源项目汇总,涉及到 Android 开发的方方面面,基本很全了。对 Android 开发感兴趣...
抽屉菜单 MaterialDrawer ★7337 - 安卓抽屉效果实现方案 Side-Menu.Android ★3865 - 创意边侧菜单 FlowingDrawer ★1744 - 向右滑动流动抽屉效果 SlidingRootNav ★1338 - 仿DrawerLa...
最近做了一个Android UI相关开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个star。 抽屉菜单 MaterialDrawer ★7337 - 安卓抽屉效...
蒙着眼睛画画,过不了多久,就忘了自己本有的状态。
我爱你,你知道吗? 姐姐健康 附近有好吃的吗? 不是不爱你 那一线天
对《极简生活》这本书来说,真是太适合我现在的一个状况了。因为我每天都在买—整理—丢,形成了恶性循环。说实话,我也有把想买的东西记录下来再买,但就这样,我还是会买到一些原本不需要的东西,因为有些东西纯粹是因为好看,又或跟老公赌气就买回来了。还有就是总担心要用的东西临时又没...
梦里不知眠,觉后眠何在。试问眠身与梦身,那个能祇对。醉后有人醒,醒了无人醉。要识三千与大千,不在微尘外。 据说陈瓘还是个很厉害的理学家,同时精研儒学与佛学。以上这些学问,我都一窍不通。所以读完这首词,有点云里雾里,不明觉厉…… 第一段,做梦的时候不知道我睡着了,醒了以后也不...}

我要回帖

更多关于 Android入门简书 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信