Android 自定義九宮格手勢鎖
預(yù)覽效果圖如下:

主要的方法是重寫View.onTouchEvent( MotionEvent event ) , 常用的三個(gè)操作:ACTION_DOWN 手指觸摸屏幕 ; ACTION_UP 手指離開屏幕;
ACTION_MOVE手指在屏幕滑動(dòng)。
如果該方法返回true ,表示該事件已經(jīng)被View處理,不再向上層的View或Activity傳遞 ; 如果返回false, 表示事件未處理,繼續(xù)傳遞。
具體代碼如下:
package com.ninegrid;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by Administrator on 2017/6/24.
*/
public class SuduView extends View {
//定義默認(rèn)常量
private static final int DEFAULT_CELL_WIDTH = 200 ;
private static final int DEFAULT_CELL_STROKE_WIDTH = 10 ;
private static final int DEFAULT_SPACE = 100 ;
//九宮格數(shù)組
private Cell mCells[] = new Cell[9] ;
//直徑
private int mCellWidth;
//半徑
private int mCellRadius;
//邊框?qū)挾?
private int mCellStrokeWidth;
//空白部分
private int mSpace ;
//定義畫筆
private Paint mPaintNormal ;
private Paint mPaintSelected ;
private float mCurrentX ;
private float mCurrentY ;
//判斷是否結(jié)束的標(biāo)識(shí)
private boolean mFinish = false ;
private StringBuffer mSbSelected = new StringBuffer(20);
public SuduView(Context context) {
super(context);
init();
}
public SuduView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SuduView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
//初始化畫筆
mCellWidth = DEFAULT_CELL_WIDTH ;
mCellRadius = DEFAULT_CELL_WIDTH >> 1 ;
mCellStrokeWidth = DEFAULT_CELL_STROKE_WIDTH ;
mSpace = DEFAULT_SPACE ;
mPaintNormal = new Paint();
mPaintNormal.setColor(Color.WHITE);
mPaintNormal.setStrokeWidth(mCellStrokeWidth);
mPaintNormal.setStyle(Paint.Style.STROKE);
mPaintNormal.setAntiAlias(true);
mPaintSelected = new Paint();
mPaintSelected.setColor(Color.CYAN);
mPaintSelected.setStrokeWidth(mCellStrokeWidth);
mPaintSelected.setStyle(Paint.Style.STROKE);
mPaintSelected.setAntiAlias(true);
Cell cell ;
float x;
float y;
//計(jì)算每個(gè)格子的坐標(biāo)
for( int i = 0 ; i < 9 ; i ++ ){
x = mSpace * ( i%3 + 1 ) + mCellRadius + mCellWidth * ( i%3 ) ;
y = mSpace * ( i/3 + 1 ) + mCellRadius + mCellWidth * ( i/3 ) ;
cell = new Cell(x , y);
mCells[i] = cell ;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCell(canvas);
drawLine(canvas);
}
//繪制連接線
private void drawLine( Canvas canvas ){
if("".equals(mSbSelected.toString())){
return;
}
String[] selectedIndexs = mSbSelected.toString().split(",");
Cell cell = mCells[Integer.valueOf(selectedIndexs[0])];
Cell nextCell ;
//繪制每兩個(gè)格子中心點(diǎn)之間的連接線
if( selectedIndexs.length > 1) {
for (int i = 1; i < selectedIndexs.length; i++) {
nextCell = mCells[Integer.valueOf(selectedIndexs[i])];
canvas.drawLine(cell.getCenterX(), cell.getCenterY(), nextCell.getCenterX(), nextCell.getCenterY(), mPaintSelected);
cell = nextCell;
}
}
//繪制格子到其他空白位置的連接線
if( !mFinish ) {
canvas.drawLine(cell.getCenterX(), cell.getCenterY(), mCurrentX, mCurrentY, mPaintSelected);
}
}
private void drawCell( Canvas canvas ){
for ( int i = 0 ; i < 9 ; i ++ ){
canvas.drawCircle(mCells[i].getCenterX(), mCells[i].getCenterY() , mCellRadius ,
mCells[i].isSelected() ? mPaintSelected : mPaintNormal );
}
}
//處理點(diǎn)擊事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch ( event.getAction()){
case MotionEvent.ACTION_DOWN:
//如果手指已經(jīng)松開,則所有格子變?yōu)槌跏紶顟B(tài)
if( mFinish ){
for ( int i = 0 ; i < 9 ; i ++ ){
mCells[i].setSelected(false);
}
mFinish = false ;
mSbSelected.delete(0,mSbSelected.length());
invalidate();
return false;
}
handleDownEvent(event);
break;
//松開則結(jié)束
case MotionEvent.ACTION_UP:
mFinish = true ;
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(event);
break;
}
//表示已處理,不向上傳遞
return true ;
}
//處理手指移動(dòng)的事件
private void handleMoveEvent( MotionEvent event ){
int index = findCellIndex(event.getX(),event.getY());
if( index != -1 ){
mCells[index].setSelected(true);
mSbSelected.append(index).append(",");
}
invalidate();
mCurrentX = event.getX();
mCurrentY = event.getY();
}
//處理手指按下的事件
private void handleDownEvent( MotionEvent event){
int index = findCellIndex(event.getX(),event.getY());
if( index != -1 ){
mCells[index].setSelected(true);
mSbSelected.append(index).append(",");
invalidate();
}
mCurrentX = event.getX();
mCurrentY = event.getY();
}
//根據(jù)坐標(biāo)判斷點(diǎn)擊的哪個(gè)格子
private int findCellIndex( float x , float y){
float cellX ;
float cellY ;
int result = -1 ;
for( int i = 0 ; i < 9 ; i ++ ){
if( mCells[i].isSelected()){
continue;
}
//獲取每個(gè)格子的坐標(biāo)
cellX = mCells[i].getCenterX();
cellY = mCells[i].getCenterY();
//計(jì)算按下的點(diǎn)到每個(gè)格子的距離
float tempX = cellX - x ;
float tempY = cellY - y ;
float distance = (float) Math.sqrt(tempX * tempX + tempY * tempY);
//如果點(diǎn)擊的位置在某個(gè)格子的圓內(nèi)
if( distance < mCellRadius ){
result = i ;
break;
}
}
//返回該格子的位置
return result ;
}
}
最后在布局文件中引用該View即可,若想實(shí)現(xiàn)更高的定制性,可以仿照上一篇文章重寫View的onMearsure方法并增加自定義屬性。
以上所述是小編給大家介紹的Android 自定義九宮格手勢鎖,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android?Settings?跳轉(zhuǎn)流程方法詳解
這篇文章主要為大家介紹了Android?Settings跳轉(zhuǎn)流程方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
android實(shí)現(xiàn)上下左右滑動(dòng)界面布局
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)上下左右滑動(dòng)的界面布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
android中DatePicker和TimePicker的使用方法詳解
這篇文章主要介紹了android中DatePicker和TimePicker的使用方法,是Android中常用的功能,需要的朋友可以參考下2014-07-07
android 使用kotlin 實(shí)現(xiàn)點(diǎn)擊更換全局語言(中日英切換)
這篇文章主要介紹了android kotlin 點(diǎn)擊更換全局語言的實(shí)現(xiàn)方法,這里主要介紹中日英切換,需要的朋友可以參考下2019-11-11
android中g(shù)zip數(shù)據(jù)壓縮與網(wǎng)絡(luò)框架解壓縮
這篇文章主要為大家介紹了android中g(shù)zip數(shù)據(jù)壓縮與網(wǎng)絡(luò)框架解壓縮實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Flutter輸入框TextField屬性及監(jiān)聽事件介紹
這篇文章主要介紹了Flutter輸入框TextField屬性及監(jiān)聽事件介紹,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2021-11-11
Android 中HttpURLConnection與HttpClient使用的簡單實(shí)例
這篇文章介紹了Android 中HttpURLConnection與HttpClient使用的簡單實(shí)例,有需要的朋友可以參考一下2013-10-10

