国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android開發之如何自定義數字鍵盤詳解

2019-10-22 18:28:01
字體:
來源:轉載
供稿:網友

前言

這篇文章是介紹Android中自定義鍵盤的一些套路,通過定義一個android/268852.html">數字鍵盤為例,本篇的文章語言是基于Kotlin實現的,如果還沒有用或者不熟悉該語言的同學,可以自己補習,我之前也寫過入門文章。

android,數字鍵盤,安卓自定義數字鍵盤,kotlin,教程
效果圖

github:源碼傳送門

本地下載:源碼傳送門

加載鍵盤存儲鍵屬性的XML描述

我們下面的介紹都是依靠上圖的實現來展開的,首先是軟鍵盤的布局,我們需要我們的res/xml目錄下創建一個xml文件,根節點就是Keyboard,然后就是鍵盤的每一行Row,每一行中可以指定每一列,也就是具體的鍵Key,代碼實現

<?xml version="1.0" encoding="utf-8"?><!--isRepeatable:長按時是否重復這個操作--><Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="1px" android:keyHeight="7%p" android:keyWidth="33.33%p" android:verticalGap="1px"> <Row android:keyHeight="6%p"> <Key android:codes="-4" android:keyIcon="@drawable/hidden" android:keyWidth="100%" /> </Row> <Row> <Key android:codes="49" android:keyLabel="1" /> <Key android:codes="50" android:keyLabel="2" /> <Key android:codes="51" android:keyLabel="3" /> </Row> <Row> <Key android:codes="52" android:keyLabel="4" /> <Key android:codes="53" android:keyLabel="5" /> <Key android:codes="54" android:keyLabel="6" /> </Row> <Row> <Key android:codes="55" android:keyLabel="7" /> <Key android:codes="56" android:keyLabel="8" /> <Key android:codes="57" android:keyLabel="9" /> </Row> <Row> <Key android:codes="46" android:keyLabel="." /> <Key android:codes="48" android:keyLabel="0" /> <Key android:codes="-5" android:isRepeatable="true" android:keyIcon="@drawable/delete" /> </Row></Keyboard>

在Keyboard節點屬性中,我們通過horizontalGap設置水平的間距,通過verticalGap設置垂直的間距,通過keyWidth設置每一個key的寬度,通過keyHeight設置。需要注意的地點是如果Keyboard ,Row和Key都可以指定寬高。通常我們可以指定在Keyboard 中設置每一個鍵的寬高就可以了。當然如果對特定行的寬高要有所調整,可以在Row 或者key上設置,例如我們示例圖中展示的最上面的一行,它的寬度比其它行都低了一點,則我們在第一行設置了屬性android:keyHeight="6%p"

在每一個key中有下面常用屬性

1、android:codes 官網介紹是說這個是該鍵的unicode 值或者逗號分隔值,當然我們也可以設置成我們想要的值,在源碼中提供了幾個特定的值

//就不解釋了,通過名字應該看得出來 public static final int KEYCODE_SHIFT = -1; public static final int KEYCODE_MODE_CHANGE = -2; public static final int KEYCODE_CANCEL = -3; public static final int KEYCODE_DONE = -4; public static final int KEYCODE_DELETE = -5; public static final int KEYCODE_ALT = -6;

2、android:keyOutputText 設置該值后,當點擊key時回調onText(text: CharSequence?)會執行,參數就是我們設置的值。

3、android:keyIcon設置key上顯示的icon

4、android:keyLabel 鍵上顯示的值

5、android:isRepeatable 當長按時是否重復該鍵設置的操作,例如我們刪除鍵可以設置此屬性。

6、android:keyEdgeFlags 該屬性有兩個值,分別是left,right,用與指定顯示在最左還是最右,一般不用此屬性。默認從左到右排列。

還有其它屬性,不在介紹,可以自己去查閱api

自定義KeyboardView

該類是用來渲染虛擬鍵盤的類,類中有一個接口OnKeyboardActionListener能檢測按鍵和觸摸動作,我們要自定義虛擬鍵盤,只需要繼承該類并實現該監聽接口即可,當然我這里并沒有實現接口,我單獨創建了一個工具類,用于將自定義鍵盤View和EditText關聯,并設置接口監聽,這些稍后介紹到再說,我們最主要關注的就是onDraw方法,它可以讓我們自定義鍵盤的繪制,隨心所欲的畫我們想要的東西。當然,我們也可以不做任何實現,它默認的有一種繪制。

class CustomKeyboardView : KeyboardView { private var mKeyBoard: Keyboard? = null constructor(context: Context, attrs: AttributeSet) : this(context, attrs,0) {} constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { // } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) mKeyBoard = this.keyboard var keys: MutableList<Keyboard.Key>? = null if (mKeyBoard != null) { keys = mKeyBoard!!.keys } if (keys != null) { for (key in keys) { //可以自定義自己的繪制(例如某個按鈕繪制背景圖片和文字,亦或者更改某個按鈕顏色等) if (key.codes[0] == -111) {//過濾指定某個鍵自定義繪制 } } } }}

在上面的onDraw方法中,我們通過this.keyboard(即java的getKeyboard方法,是KeyboardView 中的方法)獲取Keyboard對象,并通過mKeyBoard!!.keys獲取鍵盤的Key對象,即每一個鍵對象,如果我們想自定義繪制,就可以自己實現繪制,當然也可以針對個人鍵繪制,例如鍵上字體顏色,背景等。例如我們針對Key的code是 -111的自定義一些繪制操作。

 if (key.codes[0] == -111) {//過濾指定某個鍵自定義繪制  //繪制后,原來xml中的keyLabel以及keyIcon會被覆蓋,如需顯示文字  //需要自己重新繪制,要后繪制文字,否則文字不顯示  drawBackground(R.drawable.bg_keyboardview1, canvas, key)  drawTextOrIcon(canvas, key) }

背景selector

<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/btnpressed" android:state_pressed="true"/> <item android:drawable="@color/btnnormal"/></selector>

需要注意的是需要先繪制背景,再繪制文字或icon,否則文字或者icon就看不到了,相信你肯定知道為啥,真不知道的話那....

 //繪制背景 fun drawBackground(drawableId: Int, canvas: Canvas, key: Keyboard.Key) { var drawable = resources.getDrawable(drawableId) var drawableState: IntArray = key.currentDrawableState if (key.codes[0] != 0) {  drawable.state=drawableState } drawable.bounds = Rect(key.x, key.y, key.x + key.width, key.height + key.y) drawable.draw(canvas) }

繪制背景前先通過key.currentDrawableState(java的getCurrentDrawableState() 方法,后面不在提了)獲取當前的狀態,然后設置到drawable,然后通過Rect指定繪制的區域。Rect參數分別是左上右下。key.x,key.對應的就是該key的左上角的坐標,則left=key.xtop=key.y, right=key.x+key.width, bottom=key.y+key.height然后調用 drawable.draw(canvas)開始繪制。

繪制完成背景之后,我們開始繪制文字或者icon。

 //繪制文字或圖標 fun drawTextOrIcon(canvas: Canvas, key: Keyboard.Key) { var bounds = Rect() var paint = Paint() paint.color = Color.WHITE paint.isAntiAlias = true paint.textAlign = Paint.Align.CENTER paint.typeface = Typeface.DEFAULT if (key.label != null) {  var label = key.label.toString()  //為了將字體大小與默認繪制的Label字體大小相同,需要反射獲取默認大小。然后在此處設置文字大小  //還有一種取巧的方法在布局文件keyboardview中設置keyTextSize,labelTextSize  var field = KeyboardView::class.java.getDeclaredField("mLabelTextSize")  field.isAccessible = true  var labelTextSize = field.get(this) as Int  paint.textSize = labelTextSize.toFloat()  paint.getTextBounds(label, 0, label.length, bounds)  canvas.drawText(label, (key.x + key.width / 2).toFloat(), (key.y + key.height / 2 + bounds.height() / 2).toFloat(), paint) } else if (key.icon != null) {  key.icon.bounds = Rect(key.x + (key.width - key.icon.intrinsicWidth) / 2, key.y + (key.height - key.icon.intrinsicHeight) / 2, key.x + (key.width - key.icon.intrinsicWidth) / 2 + key.icon.intrinsicWidth, key.y + (key.height - key.icon.intrinsicHeight) / 2 + key.icon.intrinsicHeight)  key.icon.draw(canvas) } }

通過上面的代碼,我們做了下判斷如果有label的時候就繪制文字,如果沒有但是有icon就繪制icon,否則不做處理。在這里可以指定繪制文字的大小,顏色等。需要注意的一點是文字大小,為了和顯示的其他默認繪制key的大小相同,需要獲取KeyboardView中的mLabelTextSize或者mKeyTextSize,因為該變量沒有提供暴露方法,所以需要我們反射操作。當然還有一種取巧的方法,我們可以在xml中指定字體大小,在此設置成相同大小。對于坐標區域的計算上面已經做了分析。

布局使用

<?xml version="1.0" encoding="utf-8"?><!--background:整個鍵盤的背景色keyBackground :設置鍵的背景keyPreviewHeight:預覽高度keyPreviewLayout :設置預覽布局keyPreviewOffset :設置反饋的垂直偏移量keyTextColor :設置key標簽文字顏色keyTextSize:設置key標簽字體大小labelTextSize:設置帶文本和圖標的鍵上個的文本的小大--><com.code4android.keyboard.CustomKeyboardView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/keyboard_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/keyborad_line_color" android:focusable="true" android:focusableInTouchMode="true" android:keyBackground="@drawable/bg_keyboardview" android:keyPreviewHeight="35dp" android:keyPreviewLayout="@layout/keyboard_key_preview" android:keyPreviewOffset="0dp" android:keyTextColor="#8a8a8a" android:keyTextSize="18sp" android:labelTextSize="18sp" android:paddingTop="0dp" android:shadowColor="#fff" android:shadowRadius="0.0" />

我們創建了自定義的View之后,需要再創建上面layout供加載。keyBackground屬性是設置Key的背景,一般我們可以設置一個selected選擇器。keyPreviewHeight設置預覽的高度,即我們點擊時會有一個提示效果。keyPreviewLayout是我們預覽的布局,它需要是一個TextView 。keyPreviewOffset是預覽的偏移量,keyTextColor設置key字體顏色,shadowRadius我們一般設置為0,它表示字體的陰影,如果不設置0.看起來回模糊。

創建工具類

在工具類中創建了兩個構造方法

 constructor(activity: Activity) : this(activity, true, false) /** * @param activity * @param isRandom 是否時隨機鍵盤 * @param mIsDecimal 是否支持小數輸入 */ constructor(activity: Activity, isRandom: Boolean, isDecimal: Boolean) { mActivity = activity mIsRandom = isRandom mIsDecimal = isDecimal mKeyboard = Keyboard(mActivity, R.xml.keyboard) addViewToRoot() }//加載自定義的鍵盤layout private fun addViewToRoot() { mKeyBoardViewContainer = mActivity.layoutInflater.inflate(R.layout.keyboardview, null) //var frameLayout: FrameLayout = mActivity.window.decorView as FrameLayout//不要直接往DecorView(狀態欄,內容,導航欄)中addView,如使用這個則最后顯示布局不全(一部分內容在導航欄區域) var frameLayout: FrameLayout = mActivity.window.decorView.find(android.R.id.content) var lp = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT) lp.gravity = Gravity.BOTTOM frameLayout.addView(mKeyBoardViewContainer, lp) mKeyBoardView = mKeyBoardViewContainer.find(R.id.keyboard_view) }

在構造方法中初始化Keyboard,以及布局文件,在代碼中我們看到我們獲取到DecorView中id為android.R.id.content的布局,該布局是FrameLayout 布局,我們創建的布局都是放在這個布局中了,對這方面不理解的可以看看我之前寫的文章深入分析setContentView。為了讓我們自定義的鍵盤顯示在最下面,設置Gravity為BOTTOM,然后通過frameLayout.addView(mKeyBoardViewContainer, lp)添加到FrameLayout 中。

除此之外,我們創建一個函數attachTo(EditText)將EditText與我們自定義的鍵盤綁定

fun attachTo(editText: EditText) { //如果editText與上次設置的是同一個對象,并且鍵盤已經正在在顯示,不再執行后續操作 if (mEditText != null && mEditText == editText && mKeyBoardView.visibility == View.VISIBLE) return mEditText = editText Log.e(TAG, "attachTo") //根據焦點及點擊監聽,來顯示或者隱藏鍵盤 onFoucsChange() //隱藏系統鍵盤 hideSystemSoftKeyboard() //顯示自定義鍵盤 showSoftKeyboard() } private fun onFoucsChange() { mEditText!!.setOnFocusChangeListener { v, hasFocus ->  Log.e(TAG, "onFoucsChange:$hasFocus" + v)  //如果獲取焦點,并且當前鍵盤沒有顯示,則顯示,并執行動畫  if (hasFocus && mKeyBoardView.visibility != View.VISIBLE) {  mKeyBoardView.visibility = View.VISIBLE  startAnimation(true)  } else if (!hasFocus && mKeyBoardView.visibility == View.VISIBLE) {  //如果當前時失去較大,并且當前在鍵盤正在顯示,則隱藏  mKeyBoardView.visibility = View.GONE  startAnimation(false)  } } mEditText!!.setOnClickListener {  Log.e(TAG, "setOnClickListener")  //根據上面焦點的判斷,如果已經獲取到焦點,并且鍵盤隱藏。再次點擊時,  // 焦點改變函數不會回調,所以在此判斷如果隱藏就顯示  if (mKeyBoardView.visibility == View.GONE) {  mKeyBoardView.visibility = View.VISIBLE  startAnimation(true)  } } } private fun hideSystemSoftKeyboard() { //11版本開始需要反射setShowSoftInputOnFocus方法設置false,來隱藏系統軟鍵盤 if (Build.VERSION.SDK_INT > 10) {  var clazz = EditText::class.java  var setShowSoftInputOnFocus: Method? = null  setShowSoftInputOnFocus = clazz.getMethod("setShowSoftInputOnFocus", Boolean::class.java)  setShowSoftInputOnFocus.isAccessible = true  setShowSoftInputOnFocus.invoke(mEditText, false) } else {  mEditText!!.inputType = InputType.TYPE_NULL } var inputMethodManager = mActivity.applicationContext.inputMethodManager inputMethodManager.hideSoftInputFromWindow(mEditText!!.windowToken, 0) }private fun showSoftKeyboard() { if (mIsRandom) {  //生成隨機鍵盤  generateRandomKey() } else {  //有序鍵盤  mKeyBoardView.keyboard = mKeyboard } mKeyBoardView.isEnabled = true //設置預覽,如果設置false,則就不現實預覽效果 mKeyBoardView.isPreviewEnabled = true //設置可見 mKeyBoardView.visibility = View.VISIBLE //指定鍵盤彈出動畫 startAnimation(true) //設置監聽 mKeyBoardView.setOnKeyboardActionListener(mOnKeyboardActionListener()) } private fun generateRandomKey() { var keys = mKeyboard.keys var numberKeys = mutableListOf<Keyboard.Key>() //保存數字 var nums = mutableListOf<Int>() //0的ASCII碼是48,之后順序加1 for (key in keys) {  //過濾數字鍵盤  if (key.label != null && "0123456789".contains(key.label)) {  nums.add(Integer.parseInt(key.label.toString()))  numberKeys.add(key)  } } var random = Random() var changeKey = 0//更改numberKeys對應的數值 while (nums.size > 0) {  var size = nums.size  var randomNum = nums[random.nextInt(size)]  var key = numberKeys[changeKey++]  key.codes[0] = 48 + randomNum  key.label = randomNum.toString()  nums.remove(randomNum) } mKeyBoardView.keyboard = mKeyboard }

具體的解釋已在代碼中體現。

設置鍵盤監聽

在上面代碼中我們看一句mKeyBoardView.setOnKeyboardActionListener(mOnKeyboardActionListener()) ,它就是設置鍵盤的監聽。OnKeyboardActionListener接口是KeyboardView的內部類,我們在此設置監聽可以指定在對應的回調種操作EditText。該接口回調方法如下

1、swipeUp()

當用戶快速將手指從下向上移動時調用

2、swipeDown 方法

當用戶快速將手指從上向下移動時調用

3、swipeLeft

當用戶快速將手指從右向左移動時調用

4、swipeRight()

當用戶快速將手指從左向右移動時調用

5、onPress(primaryCode: Int)

點擊key時調用primaryCode時對應key的codes值

6、onRelease(primaryCode: Int)

釋放key時調用

7、onKey(primaryCode: Int, keyCodes: IntArray?)

我選擇在此對EditText的編輯,onPress之后調用的。

8、onText(text: CharSequence?)

設置keyOutputText時會會回調

具體實現

 inner class mOnKeyboardActionListener : KeyboardView.OnKeyboardActionListener { override fun swipeRight() {  Log.e(TAG, "swipeRight") } override fun onPress(primaryCode: Int) {  Log.e(TAG, "onPress")  //添加震動效果  mActivity.applicationContext.vibrator.vibrate(50)  ////指定隱藏(確定)刪除不顯示預覽  mKeyBoardView.isPreviewEnabled = !(primaryCode == Keyboard.KEYCODE_DONE || primaryCode == Keyboard.KEYCODE_DELETE) } override fun onRelease(primaryCode: Int) {  Log.e(TAG, "onRelease") } override fun swipeLeft() {  Log.e(TAG, "swipeLeft") } override fun swipeUp() {  Log.e(TAG, "swipeUp") } override fun swipeDown() {  Log.e(TAG, "swipeDown") } override fun onKey(primaryCode: Int, keyCodes: IntArray?) {  Log.e(TAG, "onKey primaryCode:$primaryCode keyCodes:$keyCodes")  if (mEditText == null) throw RuntimeException("The mEditText is null,Please call attachTo method")  mEditText?.let {  var editable: Editable = it.text  var textString = editable.toString()  //獲取光標位置  var start = it.selectionStart  when (primaryCode) {   //如果是刪除鍵,editable有值并且光標大于0(即光標之前有內容),則刪除   Keyboard.KEYCODE_DELETE -> {   if (!editable.isNullOrEmpty()) {    if (start > 0) {    editable.delete(start - 1, start)    } else {    }   } else {   }   }   Keyboard.KEYCODE_DONE -> {   hideSoftKeyboard()   mOnOkClick?.let {    //點擊確定時,寫一個回調,如果你對有確定的需求    it.onOkClick()   }   }   else -> {   // 由于promaryCode是用的ASCII碼,則直接轉換字符即可,46是小數點   if (primaryCode != 46 ) {    //如果點擊的是數字,不是小數點,則直接寫入EditText,由于我codes使用的是ASCII碼,    // 則可以直接轉換為數字。當然可以你也可以獲取label,或者根據你自己隨便約定。    editable.insert(start, Character.toString(primaryCode.toChar()))   } else {    //如果點擊的是逗號    if (mIsDecimal && primaryCode == 46) {    if ("" == textString) {     //如果點的是小數點,并且當前無內容,自動加0     editable.insert(start, "0.")    } else if (!textString.contains(".")) {     //當前內容不含有小數點,并且光標在第一個位置,依然加0操作     if (start == 0) {     editable.insert(start, "0.")     } else {     editable.insert(start, ".")     }    } else {     //如果是不允許小數輸入,或者允許小數,但是已經有小數點,則不操作    }    } else {    }   }   }  }  } } override fun onText(text: CharSequence?) {  Log.e(TAG, "onText:" + text.toString()) } } fun hideSoftKeyboard(): Boolean { if (mEditText == null) return false var visibility = mKeyBoardView.visibility if (visibility == View.VISIBLE) {  startAnimation(false)  mKeyBoardView.visibility = View.GONE  return true } return false } fun startAnimation(isIn: Boolean) { Log.e(TAG, "startAnimation") var anim: Animation if (isIn) {  anim = AnimationUtils.loadAnimation(mActivity, R.anim.anim_bottom_in) } else {  anim = AnimationUtils.loadAnimation(mActivity, R.anim.anim_bottom_out) } mKeyBoardViewContainer.startAnimation(anim) }

當點擊的是KEYCODE_DONE 時,調用hideSoftKeyboard函數隱藏鍵盤,并執行隱藏動畫,動畫的xml文件就不在貼出了。

具體使用方式如下

 keyboardUtli = KeyBoardUtil(this@KeyBoardDemoActivity) et_keyboard.setOnTouchListener { v, event ->  keyboardUtli?.attachTo(et_keyboard)  //設置是否可以輸入小數  keyboardUtli?.mIsDecimal = true  false } et_keyboard2.setOnTouchListener { v, event ->  keyboardUtli?.attachTo(et_keyboard2)  keyboardUtli?.mIsDecimal = false  false }

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌鲁木齐市| 西乡县| 施秉县| 临清市| 印江| 邹城市| 武夷山市| 荔波县| 黄石市| 沾化县| 中卫市| 四平市| 姚安县| 永新县| 麻阳| 治县。| 周至县| 宝丰县| 谢通门县| 石景山区| 孙吴县| 扶余县| 四子王旗| 抚松县| 自治县| 红河县| 富阳市| 广灵县| 宜川县| 崇左市| 余干县| 苏尼特右旗| 昔阳县| 攀枝花市| 密山市| 巴彦县| 沂源县| 潼关县| 拉萨市| 平昌县| 濮阳县|