嗯础钠,這里實(shí)現(xiàn)了手勢密碼的布局恰力,與點(diǎn)擊的實(shí)現(xiàn),因?yàn)槭菦]有密碼的簡化版所以使用的方法比較簡單珍坊。好了牺勾,廢話不多說,現(xiàn)在就來看看我們的代碼與結(jié)果吧(圖片資源我放在代碼下阵漏,有意向的人可以下載試試喲Wっ瘛)
一結(jié)果展示:
二代碼:
(1)這是我們的xml代碼,就是多了一個(gè)控件來設(shè)置背景和主控件的id履怯。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/rl_root"
>
<!--設(shè)置背景函數(shù)回还,不然的話我們的點(diǎn)控件看不清楚-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg"
android:scaleType="fitXY"/>
</RelativeLayout>
(2)這里是我們的主函數(shù)代碼
package ly.pxd.android12fir;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
float padding;//設(shè)置我們控件對于邊緣的間隔(左右)
RelativeLayout rl;//主控件變量,因?yàn)槎鄠€(gè)函數(shù)都會使用叹洲,所以就全局了
ArrayList<ImageView> dotViews;//關(guān)于ImageView類型的動態(tài)數(shù)組
mpaint dotpaint;//自定義控件的變量柠硕,同樣是因?yàn)槎鄠€(gè)地方都會使用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rl = findViewById(R.id.rl_root);//找到主控件
dotViews=new ArrayList<>();//分配空間
creatnine(R.drawable.normal, View.VISIBLE);//使用方法創(chuàng)建九個(gè)初始點(diǎn)
creatmpain();//創(chuàng)建自定義控件
creatnine(R.drawable.selected,View.INVISIBLE);//注意這里是采用了分層的思想,讓點(diǎn)擊的按鈕對線進(jìn)
// 行部分覆蓋
dotpaint.setDotviews(dotViews);//是這9個(gè)控件能夠被我們的自定義控件調(diào)用
}
private float pixelfromdp(int size){
//屏幕密度
return size*getResources().getDisplayMetrics().density;
}//就是顯示量度的密度
private void creatnine(int res , int visible ){
//創(chuàng)建我們的點(diǎn)
padding = pixelfromdp(20);
//計(jì)算兩個(gè)點(diǎn)中心點(diǎn)之間的間距
Point p = new Point();
//記錄我們點(diǎn)的坐標(biāo)
getWindowManager()
.getDefaultDisplay()
.getSize(p);//得到我們屏幕的大小
Bitmap bitmap = BitmapFactory
.decodeResource(getResources(),res);
//獲取圖片,從而找出圖片寬高
float space = (p.x - 2 * padding - bitmap.getWidth())/2;
//間隔蝗柔,點(diǎn)之間的間隔
//確定第一個(gè)點(diǎn)的x和y
float x = padding;
float y = p.y/2 - space - bitmap.getHeight();
//使用雙重循環(huán)闻葵,進(jìn)行點(diǎn)的添加
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
//創(chuàng)建圖片視圖
ImageView iv = new ImageView(this);
iv.setBackgroundResource(res);
//設(shè)置位置
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams
(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int)(x+space*j);//注意i,j的取值都是0,1癣丧,2所以space是我們點(diǎn)間隔
//而padding只是我們點(diǎn)與左右邊緣的間隔
params.topMargin = (int)(y+space*i);
iv.setVisibility(visible);//設(shè)置可視屬性
//添加視圖
rl.addView(iv,params);
if(res==R.drawable.selected){//如果是點(diǎn)擊之后的按鈕槽畔,我們就添加,因?yàn)槲覀儾僮鞯木褪沁@個(gè)控件
dotViews.add(iv);
}
}
}
}
private void creatmpain(){
dotpaint=new mpaint(this);//分配空間
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);//與屏幕寬高相同
rl.addView(dotpaint,params);//添加
}
}
(2)這里是我們的自定義控件代碼
package ly.pxd.android12fir;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import java.util.ArrayList;
public class mpaint extends View {
//操作點(diǎn)的數(shù)組
private ArrayList<ImageView> dotviews;
//點(diǎn)擊了的點(diǎn)集合胁编,我們要進(jìn)行清空
private ArrayList<ImageView> selectedots;
//畫了之后路徑的集合
private ArrayList<Path> paths ;
//畫的起始點(diǎn)位置
Point startpoint;
//終點(diǎn)位置
Point endpoint;
//畫筆
Paint dotpaint;
public mpaint(Context context) {
super(context);
//我直接在這里初始化厢钧,其實(shí)可以構(gòu)建函數(shù),那樣看起來簡單點(diǎn)
//分配空間
selectedots=new ArrayList<>();
paths=new ArrayList<>();
dotviews=new ArrayList<>();
//設(shè)置畫筆屬性
dotpaint=new Paint(Paint.ANTI_ALIAS_FLAG);
dotpaint.setColor(Color.WHITE);
dotpaint.setStrokeWidth(20);
dotpaint.setStyle(Paint.Style.STROKE);
}
//得到我們的操作點(diǎn)
public void setDotviews(ArrayList<ImageView> dotviews) {
this.dotviews = dotviews;
}
//畫函數(shù)嬉橙,因?yàn)樵谖覀兂绦蜻\(yùn)用的時(shí)候它就會調(diào)用這個(gè)函數(shù)早直,所
// 以要確保這個(gè)函數(shù)不出錯
@Override
protected void onDraw(Canvas canvas) {
if(paths.size()>0) {
for (Path path : paths) {
canvas.drawPath(path, dotpaint);
}
}
if(startpoint!=null&&endpoint!=null){
canvas.drawLine(startpoint.x,startpoint.y,endpoint.x,endpoint.y,dotpaint);
}
}
//觸摸函數(shù)
@Override
public boolean onTouchEvent(MotionEvent event) {
//得到我們點(diǎn)擊手機(jī)時(shí)的位置
float x = event.getX();
float y = event.getY();
ImageView temp;
//使用switch函數(shù)能夠方便我們對于點(diǎn)擊事件的整理
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//調(diào)用函數(shù),判斷是不是在點(diǎn)控件內(nèi)
temp = panduan(x,y);
if(temp!=null){
//設(shè)置可視化函數(shù)
temp.setVisibility(View.VISIBLE);
//記錄位置
startpoint=new Point((int)(temp.getPivotX()+temp.getX()),(int)(temp.getPivotY()
+temp.getY()));
//添加市框,這個(gè)點(diǎn)已經(jīng)點(diǎn)過
selectedots.add(temp);
}
break;
case MotionEvent.ACTION_MOVE:
//判斷
temp = panduan(x,y);
//不在點(diǎn)控件內(nèi)的時(shí)候霞扬,記錄終點(diǎn)坐標(biāo)
if(temp==null){
endpoint = new Point((int)x,(int)y);
invalidate();
}else{
if(startpoint==null){
//判斷是不是第一個(gè)點(diǎn)
temp.setVisibility(View.VISIBLE);
startpoint=new Point((int)(temp.getPivotX()+temp.getX()),(int)(temp.getPivotY()
+temp.getY()));
}else{
//如果不是第一個(gè)點(diǎn)的時(shí)候
temp.setVisibility(View.VISIBLE);
//記錄與上一個(gè)點(diǎn)的路徑
Path path = new Path();
path.moveTo(startpoint.x,startpoint.y);
path.lineTo((temp.getPivotX()+temp.getX()),(temp.getPivotY()
+temp.getY()));
//添加到我們的動態(tài)數(shù)組
paths.add(path);
//將這個(gè)點(diǎn)設(shè)置為我們的起始點(diǎn)
startpoint=new Point((int)(temp.getPivotX()+temp.getX()),(int)(temp.getPivotY()
+temp.getY()));
//為了美觀,即不在點(diǎn)的控件內(nèi)部滑動時(shí)![3C2E261C17A51AC1D171A263C1B07407.jpg](https://upload-images.jianshu.io/upload_images/18961721-67c054fe6e130222.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
顯示線
endpoint=startpoint;
//調(diào)用onDraw函數(shù)
invalidate();
}
//這個(gè)點(diǎn)已經(jīng)被點(diǎn)擊了
selectedots.add(temp);
}
break;
case MotionEvent.ACTION_UP:
//松手的時(shí)候進(jìn)行刷新
cleardots();
break;
}
return true;
}
//刷新函數(shù)
private void cleardots(){
for(ImageView temp:selectedots){
temp.setVisibility(INVISIBLE);
}
//清空我們的數(shù)組
selectedots.clear();
paths.clear();
//起始點(diǎn)與終點(diǎn)都設(shè)置為空
startpoint=null;
endpoint=null;
}
//判斷函數(shù)拾给,判斷點(diǎn)擊的是不是在點(diǎn)控件內(nèi)
private ImageView panduan(float x , float y ){
//使用for循環(huán)進(jìn)行點(diǎn)控件的遍歷祥得,在返回那個(gè)點(diǎn)控件兔沃,不在返回空
for(ImageView temp : dotviews){
float locax=temp.getX();
float locay=temp.getY();
if((x>=locax&&x<=locax+temp.getWidth())&&(y>=locay&&y<=locay+temp.getHeight())){
return temp;
}
}
return null;
}
}
三這是我這些代碼用到的圖片文件:
圖片放在這里喲:
資源:
(1)背景
(2)未點(diǎn)擊按鈕(是白色的蒋得,所以看不到)
(3)已點(diǎn)擊按鈕
四,誠然乒疏,懶惰了额衙,不想談什么外部的原因,因?yàn)閯e人都能做到而自己卻做不到怕吴,這也只能是自己的原因了窍侧。不過還好,現(xiàn)在努力雖然有些晚转绷,但也不是沒有救伟件。