Android之實現(xiàn)圖案解鎖

前言:本篇文章主要用于介紹實現(xiàn)圖案解鎖所學到的知識點
環(huán)境:Android studio 4.0 開發(fā)語言:Kotlin
效果展示:


image.png

主要知識點:

  • 界面布局,包括添加各種圖片和約束
  • 使用Sharedpreference存儲數(shù)據(jù)(進行簡單封裝薪韩,提供必要的功能定庵,并且使用單例模式)
  • 實現(xiàn)觸摸滑動過程中圖案的展示
  • 實現(xiàn)圖案密碼的設置和顏色,這里主要通過設tag值來實現(xiàn)

界面UI的實現(xiàn)關(guān)鍵的是合理選擇容器,這里我們優(yōu)先使用約束布局钦无,代碼量少,且易于實現(xiàn)我們想要的效果
這里主要分為3部分盖袭,中間的虛線是我們設置的guideline,這里設置了倆條失暂,分為3個部分,主要目的是便于實現(xiàn)控件的大小和約束鳄虱,第一部分是圓角圖片弟塞,不管是自定義還是實現(xiàn)第三方庫都可以實現(xiàn)圓角的效果,第二部分是中間的顯示文本醇蝴,第三部分就是圖案解鎖部分宣肚,如果我們在第三部分設置一個ConstraintLayout的約束布局,那么我們想要實現(xiàn)的效果就可以用拖拽的方式添加到容器中悠栓,再設置合理的約束霉涨,便能很快實現(xiàn)想要的效果

那么如何使用Sharedpreference存儲數(shù)據(jù)呢?
具體步驟:

  • 1.獲取SharedPreference的對象惭适,通過getSharedPreference(String,int)方法笙瑟。第一個參數(shù)用于指定該存儲文件的名稱,不用加后綴癞志,第二個參數(shù)指定文件的操作模式往枷。一般用MODE_PRIVATE 私有方式存儲,其他應用無法訪問。
  • 2.設置參數(shù)错洁,必須通過一個SharedPreference.Editor對象秉宿。存儲鍵值對。只能存放Boolean屯碴,F(xiàn)loat描睦,Int,Long导而,String 五種類型忱叭。editor.putXxx("key","value")。
  • 3.通過editor.commit()提交數(shù)據(jù)今艺。也可以通過clean(),remove()清除韵丑。
  • 4.數(shù)據(jù)存儲在Android系統(tǒng)的 /data/data/"app package name"/shared_prefs 目錄下的一個.xml文件。

這里我們還進行了簡單的封裝虚缎,加上單例模式撵彻,更好的實現(xiàn)我們想要功能的訪問

import android.annotation.SuppressLint
import android.content.Context

class SharedPreferenceUtil private constructor() {

    private val key = "PASSWORD"

    /**
    * 單例模式
    * */
    companion object {

        private var mContext: Context? = null

        private var instance: SharedPreferenceUtil? = null


        fun getInstance(context: Context): SharedPreferenceUtil {
            mContext = context
            if (instance == null) {
                instance = SharedPreferenceUtil()
            }
            return instance!!
        }
    }

    /**
     * 保存圖案密碼
     * */
    @SuppressLint("CommitPrefEdits")
    fun savePassword(pwd: String) {
        //獲取SharedPreferences對象
        mContext?.getSharedPreferences("config", Context.MODE_PRIVATE).also {
            val edit = it?.edit()
            //寫入數(shù)據(jù)
            edit?.putString(key, pwd)
            edit?.apply()
        }
    }

    /**
     * 獲取保存的數(shù)據(jù)(這里就是圖案密碼)
     * */
    fun getPassword(): String? {
        mContext?.getSharedPreferences("config", Context.MODE_PRIVATE).also {
            return it?.getString(key,null)
        }
    }
}

接下來就是實現(xiàn)圖案解鎖功能了,那么如何實現(xiàn)呢?
這里主要是通過將觸摸點坐標轉(zhuǎn)換為相對于根容器实牡,也就是上面我們提到的約束布局容器的坐標千康,然后判斷觸摸點是否在某一個圓內(nèi),是的話就顯示選中狀態(tài)的效果(默認不可見)

獲取狀態(tài)欄高度铲掐,使用懶加載,只加載一次

/**
     * 獲取狀態(tài)欄高度值桩,使用懶加載摆霉,只加載一次
     * */
    private val barHeight:Int by lazy{
        //獲取屏幕尺寸
        val display = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(display)
        //獲取空白區(qū)域尺寸
        val rect = Rect()
        window.findViewById<ViewGroup>(Window.ID_ANDROID_CONTENT).getDrawingRect(rect)
        display.heightPixels - rect.height()
    }

將觸摸點的坐標轉(zhuǎn)化為相對容器的坐標

 /**
     * 將觸摸點的坐標轉(zhuǎn)化為相對容器的坐標
     * */
    private fun convertPointAsContainer(event: MotionEvent):Point{
        return Point().apply {
            x = (event.x.minus(mContainer.x)).toInt()
            y = (event.y - barHeight - mContainer.y).toInt()
        }
    }

獲取當前觸摸點所在的圓

 /**
     * 獲取當前觸摸點所在的圓
     * */

    private fun getCurrPointOfCircle(point: Point):ImageView?{
        for (dot in dots){
            //遍歷判斷是否包含當前觸摸點
            getRect(dot).also {
                if (it.contains(point.x,point.y)){
                    return dot
                }
            }
        }
        return null
    }

    /**
     * 獲取當前控件對應的Rect
     * */
    private fun getRect(v:ImageView) = Rect(v.left,v.top,v.right,v.bottom)

點亮圓

 /**
     * 點亮圓
     * */
    private fun setSmallCircleVisible(v: ImageView) {
        v.visibility = View.VISIBLE
        selectedViews.add(v)
        password.append(v.tag)
        lastSelectView = v
        scaleAnimation(v, true)
    }

點亮線

  //記錄點亮的上一個圓
  private var lastSelectView: ImageView? = null

這里首先記錄上一個觸摸點所在圓,然后根據(jù)當前觸摸點所在圓的tag值和上一個圓的tag拼接找到對應的線的tag值奔坟,再根據(jù)tag值找到線携栋,然后點亮這條線

 /**
     * 點亮線
     * */
    private fun setLineVisible(v: ImageView) {
        //連線
        val lTag = (lastSelectView?.tag as String).toInt()
        val cTag = (v.tag as String).toInt()
        val lineTag = if (lTag > cTag) cTag * 10 + lTag else lTag * 10 + cTag
        //判斷是否有這條線,如果有咳秉,點亮
        if (tags.contains(lineTag)) {
            //先點亮這個點
            if (v.visibility != View.VISIBLE) {
                setSmallCircleVisible(v)
            }
            //再點亮連線
            mContainer.findViewWithTag<ImageView>(lineTag.toString()).apply {
                visibility = View.VISIBLE
                selectedViews.add(this)
            }
        }
    }

然后點亮圓和線在一個方法里使用

 /**
     * 點亮點和線
     * */
    private fun setCircleAndLineVisible(v: ImageView?) {
        if (v != null && v.visibility == View.INVISIBLE) {
            //判斷是否是第一個點亮的點
            if (lastSelectView == null) {
                setSmallCircleVisible(v)
            } else {
                setLineVisible(v)
            }
        } else {
            if (lastSelectView != null && v != null) {
                if (isLineExit(lastSelectView!!, v)) {
                    setLineVisible(v)
                }
            }
        }
    }

這里的isLineExit方法婉支,傳入兩個參數(shù),分別是上一個圓和當前圓澜建,目的是為了使兩個已經(jīng)點亮的圓之間的線點亮

 /**
     * 判斷是否存在點亮的兩個小圓之間的連線未點亮
     * */
    private fun isLineExit(last: ImageView, curr: ImageView): Boolean {
        if (last.visibility == View.VISIBLE && curr.visibility == View.VISIBLE) {
            return true
        }
        return false
    }

接下來是密碼設置和保存向挖,主要使用Sharedpreference來記錄用戶設置的密碼

  /**
     * 判斷兩次密碼是否一致
     * */
    private fun isPasswordSetSucceed(first: String, second: String) {
        if (first == second) {
            mTextView.text = "設置密碼成功"
            //保存密碼
            SharedPreferenceUtil.getInstance(this).savePassword(first)
            orgPassWord = SharedPreferenceUtil.getInstance(this).getPassword()
        } else {
            mTextView.text = "兩次密碼不一致,請重新設置密碼"
            firstPassWord = null
        }
    }

最后如果想在觸摸小圓上加一點動畫炕舵,可以在觸摸時放大或縮小圓點以增強用戶使用感

 /**
     * 縮放動畫
     * */
    private fun scaleAnimation(v: ImageView, flag: Boolean) {
        AnimationUtils.loadAnimation(this, R.anim.scale_anim_set).apply {
            duration = 200
            fillAfter = true
            if (flag) {
                v.startAnimation(this)
            } else {
                v.clearAnimation()
            }
        }
    }

這里的flag參數(shù)的目的是何之,便于控制動畫的開啟和取消,當我們觸摸時咽筋,flag傳入?yún)?shù)為true,當我們松手時溶推,應該取消動畫,這時flag傳入?yún)?shù)便為false
開啟動畫

scaleAnimation(v, true)

取消動畫(松手時使用)

scaleAnimation(v, false)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蒜危,更是在濱河造成了極大的恐慌虱痕,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辐赞,死亡現(xiàn)場離奇詭異部翘,居然都是意外死亡,警方通過查閱死者的電腦和手機占拍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門略就,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晃酒,你說我怎么就攤上這事表牢。” “怎么了贝次?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵崔兴,是天一觀的道長。 經(jīng)常有香客問我蛔翅,道長敲茄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任山析,我火速辦了婚禮堰燎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笋轨。我一直安慰自己秆剪,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布爵政。 她就那樣靜靜地躺著仅讽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钾挟。 梳的紋絲不亂的頭發(fā)上洁灵,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音掺出,去河邊找鬼徽千。 笑死,一個胖子當著我的面吹牛蛛砰,可吹牛的內(nèi)容都是我干的罐栈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼泥畅,長吁一口氣:“原來是場噩夢啊……” “哼荠诬!你這毒婦竟也來了琅翻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柑贞,失蹤者是張志新(化名)和其女友劉穎方椎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钧嘶,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡棠众,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了有决。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闸拿。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖书幕,靈堂內(nèi)的尸體忽然破棺而出新荤,到底是詐尸還是另有隱情,我是刑警寧澤台汇,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布苛骨,位于F島的核電站,受9級特大地震影響苟呐,放射性物質(zhì)發(fā)生泄漏痒芝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一牵素、第九天 我趴在偏房一處隱蔽的房頂上張望严衬。 院中可真熱鬧,春花似錦笆呆、人聲如沸瞳步。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抱怔,卻和暖如春劣坊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屈留。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工局冰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灌危。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓康二,卻偏偏與公主長得像,于是被迫代替她去往敵國和親勇蝙。 傳聞我的和親對象是個殘疾皇子沫勿,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容