最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android自定義控件實(shí)現(xiàn)九宮格解鎖功能

 更新時(shí)間:2021年09月10日 10:10:40   作者:一生中所愛  
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)九宮格解鎖功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

最終Android九宮格解鎖效果如下

1.進(jìn)行定義實(shí)體point點(diǎn)

public class Point {
 private float x;
 private float y;
 //正常模式
 public static final int NORMAL_MODE = 1;
 //按下模式
 public static final int PRESSED_MODE = 2;
 //錯(cuò)誤模式
 public static final int ERROR_MODE = 3;

 private int state = NORMAL_MODE;
 private String mark;

 public Point(float x, float y, String mark) {
  this.x = x;
  this.y = y;
  this.mark = mark;
 }

 public float getX() {
  return x;
 }

 public void setX(float x) {
  this.x = x;
 }

 public float getY() {
  return y;
 }

 public void setY(float y) {
  this.y = y;
 }

 public int getState() {
  return state;
 }

 public void setState(int state) {
  this.state = state;
 }

 public String getMark() {
  return mark;
 }

 public void setMark(String mark) {
  this.mark = mark;
 }
}

2.自定義ScreenLockView

public class ScreenLockView extends View {
 private static final String TAG = "ScreenLockView";

 // 錯(cuò)誤格子的圖片
 private Bitmap errorBitmap;
 // 正常格子的圖片
 private Bitmap normalBitmap;
 // 手指按下時(shí)格子的圖片
 private Bitmap pressedBitmap;
 // 錯(cuò)誤時(shí)連線的圖片
 private Bitmap lineErrorBitmap;
 // 手指按住時(shí)連線的圖片
 private Bitmap linePressedBitmap;
 // 偏移量,使九宮格在屏幕中央
 private int offset;
 // 九宮格的九個(gè)格子是否已經(jīng)初始化
 private boolean init;
 // 格子的半徑
 private int radius;
 // 密碼
 private String password = "123456";
 // 九個(gè)格子
 private Point[][] points = new Point[3][3];
 private int width;
 private int height;
 private Matrix matrix = new Matrix();
 private float moveX = -1;
 private float moveY = -1;
 // 是否手指在移動(dòng)
 private boolean isMove;
 // 是否可以觸摸,當(dāng)用戶抬起手指,劃出九宮格的密碼不正確時(shí)為不可觸摸
 private boolean isTouch = true;
 // 用來存儲(chǔ)記錄被按下的點(diǎn)
 private List<Point> pressedPoint = new ArrayList<>();
 // 屏幕解鎖監(jiān)聽器
 private OnScreenLockListener listener;

 public ScreenLockView(Context context) {
  super(context);
  init();
 }


 public ScreenLockView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public ScreenLockView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }

 private void init() {
  errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_error);
  normalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_normal);
  pressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_pressed);
  lineErrorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
  linePressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
  radius = normalBitmap.getWidth() / 2;
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  if (widthSize > heightSize) {
   offset = (widthSize - heightSize) / 2;
  } else {
   offset = (heightSize - widthSize) / 2;
  }
  setMeasuredDimension(widthSize, heightSize);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  if (!init) {
   width = getWidth();
   height = getHeight();
   initPoint();
   init = true;
  }
  drawPoint(canvas);
  if (moveX != -1 && moveY != -1) {
   drawLine(canvas);
  }
 }

 // 畫直線
 private void drawLine(Canvas canvas) {

  // 將pressedPoint中的所有格子依次遍歷,互相連線
  for (int i = 0; i < pressedPoint.size() - 1; i++) {
   // 得到當(dāng)前格子
   Point point = pressedPoint.get(i);
   // 得到下一個(gè)格子
   Point nextPoint = pressedPoint.get(i + 1);
   // 旋轉(zhuǎn)畫布
   canvas.rotate(RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());

   matrix.reset();
   // 根據(jù)距離設(shè)置拉伸的長度
   matrix.setScale(getDistance(point, nextPoint) / linePressedBitmap.getWidth(), 1f);
   // 進(jìn)行平移
   matrix.postTranslate(point.getX(), point.getY() - linePressedBitmap.getWidth() / 2);


   if (point.getState() == Point.PRESSED_MODE) {
    canvas.drawBitmap(linePressedBitmap, matrix, null);
   } else {
    canvas.drawBitmap(lineErrorBitmap, matrix, null);
   }
   // 把畫布旋轉(zhuǎn)回來
   canvas.rotate(-RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());
  }

  // 如果是手指在移動(dòng)的情況
  if (isMove) {
   Point lastPoint = pressedPoint.get(pressedPoint.size() - 1);
   canvas.rotate(RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());

   matrix.reset();
   Log.i(TAG, "the distance : " + getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth());
   matrix.setScale(getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth(), 1f);
   matrix.postTranslate(lastPoint.getX(), lastPoint.getY() - linePressedBitmap.getWidth() / 2);
   canvas.drawBitmap(linePressedBitmap, matrix, null);

   canvas.rotate(-RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());
  }
 }

 // 根據(jù)point和坐標(biāo)點(diǎn)計(jì)算出之間的距離
 private float getDistance(Point point, float moveX, float moveY) {
  Point b = new Point(moveX,moveY,null);
  return getDistance(point,b);
 }

 // 根據(jù)兩個(gè)point計(jì)算出之間的距離
 private float getDistance(Point point, Point nextPoint) {
  return (float) Math.sqrt(Math.pow(nextPoint.getX() - point.getX(), 2f) + Math.pow(nextPoint.getY() - point.getY(), 2f));
 }
 private void drawPoint(Canvas canvas) {
  for (int i = 0; i < points.length; i++) {
   for (int j = 0; j < points[i].length; j++) {
    int state = points[i][j].getState();
    if (state == Point.NORMAL_MODE) {
     canvas.drawBitmap(normalBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
    } else if (state == Point.PRESSED_MODE) {
     canvas.drawBitmap(pressedBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
    } else {
     canvas.drawBitmap(errorBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
    }
   }
  }
 }

 //初始化九宮格的點(diǎn)
 private void initPoint() {
  points[0][0] = new Point(width / 4, offset + width / 4, "0");
  points[0][1] = new Point(width / 2, offset + width / 4, "1");
  points[0][2] = new Point(width * 3 / 4, offset + width / 4, "2");

  points[1][0] = new Point(width / 4, offset + width / 2, "3");
  points[1][1] = new Point(width / 2, offset + width / 2, "4");
  points[1][2] = new Point(width * 3 / 4, offset + width / 2, "5");

  points[2][0] = new Point(width / 4, offset + width * 3 / 4, "6");
  points[2][1] = new Point(width / 2, offset + width * 3 / 4, "7");
  points[2][2] = new Point(width * 3 / 4, offset + width * 3 / 4, "8");

 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (isTouch) {
   float x = event.getX();
   float y = event.getY();
   Point point;
   switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
     // 判斷用戶觸摸的點(diǎn)是否在九宮格的任意一個(gè)格子之內(nèi)
     point = isPoint(x, y);
     if (point != null) {
      point.setState(Point.PRESSED_MODE); // 切換為按下模式
      pressedPoint.add(point);
     }
     break;
    case MotionEvent.ACTION_MOVE:
     if (pressedPoint.size() > 0) {
      point = isPoint(x, y);
      if (point != null) {
       if (!crossPoint(point)) {
        point.setState(Point.PRESSED_MODE);
        pressedPoint.add(point);
       }
      }
      moveX = x;
      moveY = y;
      isMove = true;
     }
     break;
    case MotionEvent.ACTION_UP:
     isMove = false;
     String tempPwd = "";
     for (Point p : pressedPoint) {
      tempPwd += p.getMark();
     }
     if (listener != null) {
      listener.getStringPassword(tempPwd);
     }

     if (tempPwd.equals(password)) {
      if (listener != null) {
       listener.isPassword(true);
       this.postDelayed(runnable, 1000);
      }

     } else {
      for (Point p : pressedPoint) {
       p.setState(Point.ERROR_MODE);
      }
      isTouch = false;
      this.postDelayed(runnable, 1000);
      if (listener != null) {
       listener.isPassword(false);
      }
     }
     break;
   }
   invalidate();
  }
  return true;
 }

 private boolean crossPoint(Point point) {
  if (pressedPoint.contains(point)) {
   return true;
  }
  return false;
 }

 public interface OnScreenLockListener {
  public void getStringPassword(String password);

  public void isPassword(boolean flag);
 }

 public void setOnScreenLockListener(OnScreenLockListener listener) {
  this.listener = listener;
 }

 private Point isPoint(float x, float y) {
  Point point;
  for(int i = 0; i<points.length;i++){
   for (int j = 0; j < points[i].length; j++) {
    point = points[i][j];
    if (isContain(point, x, y)) {
     return point;
    }
   }
  }
  return null;
 }

 private boolean isContain(Point point, float x, float y) {
  return Math.sqrt(Math.pow(x - point.getX(), 2f) + Math.pow(y - point.getY(), 2f)) <= radius;
 }
 private Runnable runnable = new Runnable() {
  @Override
  public void run() {
   isTouch = true;
   reset();
   invalidate();
  }
 };

 // 重置格子
 private void reset(){
  for (int i = 0; i < points.length; i++) {
   for (int j = 0; j < points[i].length; j++) {
    points[i][j].setState(Point.NORMAL_MODE);
   }
  }
  pressedPoint.clear();
 }
}

3.RotateDegress類

public class RotateDegrees {
 public static float getDegrees(Point a, Point b){
  float degrees = 0 ;
  float aX = a.getX();
  float aY = a.getY();
  float bX = b.getX();
  float bY = b.getY();
  if(aX == bX){
   if(aY<bY){
    degrees = 90;
   }else{
    degrees = 270;
   }
  }else if(bY == aY){
   if(aX<bX){
    degrees = 0 ;
   }else{
    degrees = 180;
   }

  }else{
   if(aX>bX){
    if(aY>bY){
     degrees = 180 + (float)(Math.atan2(aY-bY,aX-bX)*180/Math.PI);
    }else{
     degrees = 180 - (float)(Math.atan2(bY -aY,aX - bX)*180/Math.PI);
    }

   }else{
    if(aY>bY){
     degrees = 360 -(float)(Math.atan2(aY - bY,bX-aX)*180/Math.PI);
    }else{
     degrees = (float)(Math.atan2(bY - aY,bX - aX)*180/Math.PI);
    }
   }
  }
  return degrees;
 }

 public static float getDegrees(Point a, float bX,float bY){
  Point b = new Point(bX,bY,null);
  return getDegrees(a,b);
 }
}

用到的圖片資源

4.MainActivity中使用

public class MainActivity extends AppCompatActivity {

 private ScreenLockView screenLockView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  screenLockView = (ScreenLockView) findViewById(R.id.slv);
  screenLockView.setOnScreenLockListener(new ScreenLockView.OnScreenLockListener() {
   @Override
   public void getStringPassword(String password) {

   }

   @Override
   public void isPassword(boolean flag) {
    String content;
    if (flag) {
     content = "密碼正確";

    } else {
     content = "密碼錯(cuò)誤";
    }
    Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();

   }
  });
 }
}

5.布局文件

<?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:id="@+id/activity_main"
 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.example.admin.ninegridunlock.MainActivity">

 <com.example.admin.ninegridunlock.ScreenLockView
  android:id="@+id/slv"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
</RelativeLayout>

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Kotlin圖文講解多語言支持實(shí)現(xiàn)方法

    Kotlin圖文講解多語言支持實(shí)現(xiàn)方法

    這篇文章主要介紹了Kotlin多語言支持實(shí)現(xiàn)方法,在Android開發(fā)中,我們?nèi)绾沃С侄嗾Z言APP呢,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值
    2023-02-02
  • 揭秘Android視圖繪制的流程步驟

    揭秘Android視圖繪制的流程步驟

    在Android的UI中,View是至關(guān)重要的一個(gè)組件,它是用戶界面的基本構(gòu)建塊,在View的繪制過程中,涉及到很多重要的概念和技術(shù),本文將詳細(xì)介紹Android?View的繪制過程,讓你能夠更好地理解和掌握Android的UI開發(fā),需要的朋友可以參考下
    2023-06-06
  • Android中發(fā)送有序廣播案例代碼

    Android中發(fā)送有序廣播案例代碼

    本篇文章主要介紹了Android中發(fā)送有序廣播案例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • 搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法

    搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法

    本篇文章主要介紹了搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android自定義可標(biāo)記日歷效果

    Android自定義可標(biāo)記日歷效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義可標(biāo)記日歷效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Android學(xué)習(xí)項(xiàng)目之簡易版微信為例(一)

    Android學(xué)習(xí)項(xiàng)目之簡易版微信為例(一)

    這篇文章主要以簡易版微信為例,為大家介紹了Android簡易版微信項(xiàng)目的基礎(chǔ)知識(shí),感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android 資源混淆的方案及注意事項(xiàng)

    Android 資源混淆的方案及注意事項(xiàng)

    資源混淆有助于減小包體積,也可以提高被反編譯后閱讀代碼的難度。還可以應(yīng)對(duì)一些安全檢測(cè)機(jī)構(gòu)對(duì)于資源混淆要求。本文基于微信的Android資源混淆工具,實(shí)現(xiàn)資源混淆
    2021-05-05
  • Android百度地圖應(yīng)用之基本地圖功能實(shí)現(xiàn)

    Android百度地圖應(yīng)用之基本地圖功能實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Android百度地圖應(yīng)用之基本地圖功能實(shí)現(xiàn)的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android自定義View實(shí)現(xiàn)豎向滑動(dòng)回彈效果

    Android自定義View實(shí)現(xiàn)豎向滑動(dòng)回彈效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)滑動(dòng)回彈效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 安卓(Android)應(yīng)用版本更新方法

    安卓(Android)應(yīng)用版本更新方法

    Android 開發(fā)中對(duì)版本進(jìn)行檢查并更新的需求基本是所有應(yīng)用必須有的功能,可是在實(shí)際開發(fā)中有些朋友就容易忽略一些細(xì)節(jié)。本文章提供解決方案,希望對(duì)大家有所幫助
    2016-07-07

最新評(píng)論

宁阳县| 洪江市| 宁远县| 阿坝| 蒙城县| 贵定县| 新蔡县| 遵义市| 玉屏| 白山市| 仁寿县| 博乐市| 南通市| 井陉县| 仁布县| 紫云| 基隆市| 天津市| 宣威市| 孟津县| 额敏县| 如皋市| 嘉峪关市| 临江市| 子长县| 遂昌县| 合水县| 大同县| 监利县| 石狮市| 南丹县| 莆田市| 股票| 宁夏| 稷山县| 长武县| 锡林郭勒盟| 手游| 安徽省| 文登市| 新乡市|