├── app ├── .gitignore ├── img │ ├── img01.jpg │ ├── img02.jpg │ ├── img03.jpg │ └── img04.jpg ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── dimens.xml │ │ │ ├── colors.xml │ │ │ ├── style_fonts.xml │ │ │ └── styles.xml │ │ ├── drawable-xxhdpi │ │ │ ├── clear_btn.png │ │ │ ├── ic_launcher.png │ │ │ ├── ic_nav_back.png │ │ │ ├── ic_nav_share.png │ │ │ ├── loading_bg.9.png │ │ │ ├── pwd_eye_close.png │ │ │ ├── pwd_eye_open.png │ │ │ ├── bg_key_normal.9.png │ │ │ ├── bg_key_pressed.9.png │ │ │ ├── ic_launcher_round.png │ │ │ ├── ic_delete_key_normal.png │ │ │ ├── ic_delete_key_pressed.png │ │ │ ├── img_keyboard_normal.9.png │ │ │ ├── libcredit_send_sms_bg.png │ │ │ └── img_keyboard_pressed.9.png │ │ ├── drawable │ │ │ ├── white_card_bg.xml │ │ │ ├── btn_keyboard_key.xml │ │ │ ├── cmb_checked_bg.xml │ │ │ ├── kb_num_bg.xml │ │ │ ├── bg_circle_red.xml │ │ │ └── btn_bg.xml │ │ ├── anim │ │ │ ├── actionsheet_dialog_in.xml │ │ │ └── actionsheet_dialog_out.xml │ │ ├── layout │ │ │ ├── activity_title_base.xml │ │ │ ├── kb_amout_layout.xml │ │ │ ├── customkeyboard.xml │ │ │ ├── activity_main.xml │ │ │ ├── find_paypwd_activity.xml │ │ │ ├── paypwd_input_password_dialog.xml │ │ │ ├── common_title.xml │ │ │ └── c_edit_text.xml │ │ └── xml │ │ │ ├── kb_pwd.xml │ │ │ ├── kb_idcert.xml │ │ │ └── kb_number.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── example │ │ └── weioule │ │ └── inputkeyboarddemo │ │ ├── MyApplication.java │ │ ├── act │ │ ├── SecondActivity.java │ │ ├── MainActivity.java │ │ ├── FindPayPwdActivity.java │ │ └── BaseTitleActivity.java │ │ ├── view │ │ ├── AsyncImageView.java │ │ ├── CEditTextSms.java │ │ ├── CmbEditText.java │ │ └── CEditText.java │ │ ├── util │ │ ├── CountDown.java │ │ ├── AsyncImageLoaderProxy.java │ │ ├── LoaderImpl.java │ │ └── IdCardUtil.java │ │ └── keyboard │ │ ├── InputPayPwdDialog.java │ │ ├── CustomKeyboardView.java │ │ ├── InputView.java │ │ └── CumKeyboardContainer.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── caches │ └── build_file_checksums.ser ├── vcs.xml ├── runConfigurations.xml ├── gradle.xml ├── misc.xml └── codeStyles │ └── Project.xml ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/img/img01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/img/img01.jpg -------------------------------------------------------------------------------- /app/img/img02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/img/img02.jpg -------------------------------------------------------------------------------- /app/img/img03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/img/img03.jpg -------------------------------------------------------------------------------- /app/img/img04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/img/img04.jpg -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | InputKeyboardDemo 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/clear_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/clear_btn.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_nav_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_nav_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_nav_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_nav_share.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/loading_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/loading_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pwd_eye_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/pwd_eye_close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pwd_eye_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/pwd_eye_open.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_key_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/bg_key_normal.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_key_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/bg_key_pressed.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_delete_key_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_delete_key_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_delete_key_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_delete_key_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/img_keyboard_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/img_keyboard_normal.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/libcredit_send_sms_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/libcredit_send_sms_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/img_keyboard_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weioule/KeyboardInputDemo/HEAD/app/src/main/res/drawable-xxhdpi/img_keyboard_pressed.9.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/white_card_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/actionsheet_dialog_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/actionsheet_dialog_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_keyboard_key.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Nov 15 15:17:58 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cmb_checked_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/kb_num_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_circle_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 45.0dip 4 | 41.0dip 5 | 7.0dip 6 | 16dp 7 | 37.0dip 8 | 9 | 4dp 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_title_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #ffffffff 8 | #F6F6F6 9 | 10 | #ffdbe6ee 11 | #D2D5DB 12 | #4A4A4A 13 | 14 | #FD5E02 15 | 16 | #fd6e5f 17 | #fb5859 18 | #ffE01A38 19 | #FFB5B5B5 20 | 21 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/kb_amout_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/customkeyboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 22 | 23 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.example.weioule.inputkeyboarddemo" 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:28.0.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Author by weioule. 7 | * Date on 2018/11/19. 8 | */ 9 | public class MyApplication extends Application { 10 | protected static MyApplication instance; 11 | 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | instance = this; 16 | } 17 | 18 | public static MyApplication instance() { 19 | return instance; 20 | } 21 | 22 | public String getCachePath() { 23 | return "/Android/data/" + getPackageName() + "/cache/"; 24 | } 25 | 26 | public String getCacheForeverPath() { 27 | return "/Android/data/" + getPackageName() + "/cache_forever/"; 28 | } 29 | 30 | /** 31 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 32 | */ 33 | public int dip2px(float dpValue) { 34 | final float scale = getResources().getDisplayMetrics().density; 35 | return (int) (dpValue * scale + 0.5f); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/style_fonts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 13 | 14 | 18 | 19 | 23 | 24 | 28 | 29 | 33 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/xml/kb_pwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 12 | 15 | 19 | 20 | 21 | 24 | 27 | 31 | 32 | 33 | 36 | 39 | 43 | 44 | 45 | 48 | 51 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/xml/kb_idcert.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 12 | 15 | 19 | 20 | 21 | 24 | 27 | 31 | 32 | 33 | 36 | 39 | 43 | 44 | 45 | 49 | 52 | 56 | 57 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 36 | 37 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/act/SecondActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.act; 2 | 3 | import android.content.Intent; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.widget.Toast; 7 | 8 | import com.example.weioule.inputkeyboarddemo.keyboard.CumKeyboardContainer; 9 | import com.example.weioule.inputkeyboarddemo.keyboard.InputPayPwdDialog; 10 | 11 | /** 12 | * Author by weioule. 13 | * Date on 2018/11/19. 14 | */ 15 | public class SecondActivity extends MainActivity { 16 | 17 | private InputPayPwdDialog inputPayPwdDialog; 18 | 19 | @Override 20 | protected String getInputType() { 21 | addTitleText("结算中心"); 22 | mIndentityCard.setHit("请输入金额"); 23 | mIndentityCard.setLeftText("金额"); 24 | Intent intent = getIntent(); 25 | mIdInfo.setText("性别:" + intent.getStringExtra(ID_INFO_SEX) + "\n" + "出生日期:" + intent.getStringExtra(ID_INFO_BIRTHDAY)); 26 | mIdInfo.setVisibility(View.VISIBLE); 27 | okBtn.setText("确认支付"); 28 | return CumKeyboardContainer.AMOUT_TYPE; 29 | } 30 | 31 | @Override 32 | protected void clickBtn() { 33 | if (TextUtils.isEmpty(mIndentityCard.getText())) { 34 | mIndentityCard.showErrNote("金额不能为空!"); 35 | return; 36 | } 37 | showInputPaypwdDialog(); 38 | hintKeyBoard(); 39 | } 40 | 41 | private void showInputPaypwdDialog() { 42 | inputPayPwdDialog = new InputPayPwdDialog(this); 43 | inputPayPwdDialog.setInputPasswordListener(new InputPayPwdDialog.PasswordListener() { 44 | @Override 45 | public void onSubmitPwd(String password) { 46 | Toast.makeText(SecondActivity.this, "成功支付" + mIndentityCard.getText() + "元", Toast.LENGTH_SHORT).show(); 47 | } 48 | }); 49 | inputPayPwdDialog.show(); 50 | } 51 | 52 | @Override 53 | public void onBackPressed() { 54 | if (hintKeyBoard()) return; 55 | finish(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/view/AsyncImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.view; 2 | 3 | 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.support.v7.widget.AppCompatImageView; 7 | import android.util.AttributeSet; 8 | 9 | import com.example.weioule.inputkeyboarddemo.util.AsyncImageLoaderProxy; 10 | 11 | /** 12 | * Author by weioule. 13 | * Date on 2018/11/19. 14 | */ 15 | public class AsyncImageView extends AppCompatImageView { 16 | AsyncImageLoaderProxy loader; 17 | 18 | public AsyncImageView(Context context) { 19 | super(context); 20 | loader = new AsyncImageLoaderProxy(getContext().getApplicationContext()); 21 | } 22 | 23 | public AsyncImageView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | loader = new AsyncImageLoaderProxy(getContext().getApplicationContext()); 26 | } 27 | 28 | /** 29 | * 缓存文件到指定路径;当缓存超过5M时,将清空缓存 30 | */ 31 | public void downloadCache2Sd(String url) { 32 | loader.downloadCache2Sd(url, new CallBack()); 33 | } 34 | 35 | /** 36 | * 图片缓存到内存,只做soft缓存 37 | */ 38 | public void downloadCache2memory(String url) { 39 | loader.downloadCache2memory(url, new CallBack()); 40 | } 41 | 42 | /** 43 | * 缓存文件到指定路径;程序不会主动清除缓存 44 | */ 45 | public void downloadCacheForever(String url) { 46 | loader.downloadCacheForever(url, new CallBack()); 47 | } 48 | 49 | class CallBack implements AsyncImageLoaderProxy.ImageCallback { 50 | @Override 51 | public void onImageLoaded(Bitmap bitmap, String imageUrl) { 52 | if (mOnLoaderListener == null) { 53 | if (bitmap != null) { 54 | setImageBitmap(bitmap); 55 | } 56 | } else { 57 | mOnLoaderListener.loaded(bitmap); 58 | } 59 | } 60 | } 61 | 62 | public OnLoadedListener mOnLoaderListener; 63 | 64 | public void setLoadedListener(OnLoadedListener back) { 65 | this.mOnLoaderListener = mOnLoaderListener; 66 | } 67 | 68 | public interface OnLoadedListener { 69 | void loaded(Bitmap bitmap); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/res/xml/kb_number.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 |         8 | 9 |                 10 | 13 |                 14 | 17 |                 18 | 21 |                 22 | 27 |         28 | 29 |         30 | 31 |                 32 | 35 |                 36 | 39 |                 40 | 43 |                 44 |         45 | 46 |         47 | 48 |                 49 | 52 |                 53 | 56 |                 57 | 60 |                 61 | 66 |         67 | 68 |         69 | 70 |                 71 | 74 |           75 | 78 |               79 | 82 |       83 |         84 | 85 | -------------------------------------------------------------------------------- /app/src/main/res/layout/find_paypwd_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 27 | 28 | 33 | 34 | 46 | 47 | 48 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeyboardInputDemo 2 | 这是一个仿支付宝自定义软键盘的demo,分别为身份证号码、支付金额、支付密码输入定制的软键盘,以及EditText文本输入框与密码输入框的定制。 3 | 4 | 先上效果图: 5 | 6 | ![image](https://github.com/weioule/KeyboardInputDemo/blob/master/app/img/img01.jpg)   7 | ![image](https://github.com/weioule/KeyboardInputDemo/blob/master/app/img/img02.jpg)   8 | ![image](https://github.com/weioule/KeyboardInputDemo/blob/master/app/img/img03.jpg)   9 | ![image](https://github.com/weioule/KeyboardInputDemo/blob/master/app/img/img04.jpg)   10 | 11 | 12 | 13 | 一 身份证键盘 14 |   1 身份证键盘在MainActivity页面,使用时再布局中添加配置 15 | 16 | 28 | 29 |     要使用自定义的键盘记得配置:app:show_custom_keyboard="true" 30 |      31 | 32 | 2 在Activity中创建 CumKeyboardContainer: 33 | ​ 34 | 35 | mCustomKeyboardView = new CumKeyboardContainer(this, getInputType()); 36 | mCustomKeyboardView.attachKeyBoardView(); 37 | 38 | 39 | ​ 40 | 3 并为输入框CEditText配置 41 | 42 | mIndentityCard = findViewById(R.id.indentity_card); 43 | mIndentityCard.setCustomKeyboardView(mCustomKeyboardView); 44 | 45 | 4 在onBackPressed中配置回退键盘,若键盘显示则先隐藏 46 | 47 |  if (mCustomKeyboardView != null && mCustomKeyboardView.getVisibility() == View.VISIBLE) { 48 | mCustomKeyboardView.setCmbVisibility(View.GONE); 49 | } 50 |  二 数字键盘 51 | 52 |      数字键盘在SecondActivity页面,使用方法同上,只是在第二步中修改类型为金额输入: 53 | 54 | mCustomKeyboardView = new CumKeyboardContainer(this, CumKeyboardContainer.AMOUT_TYPE); 55 | 56 |  三 支付密码对话框 57 | 58 |      1 创建输入框和回调方法 59 | 60 | inputPayPwdDialog = new InputPayPwdDialog(this); 61 | inputPayPwdDialog.setInputPasswordListener(new InputPayPwdDialog.PasswordListener() { 62 | @Override 63 | public void onSubmitPwd(String password) { 64 | Toast.makeText(SecondActivity.this, "成功支付" + mIndentityCard.getText() + "元", Toast.LENGTH_SHORT).show(); 65 | } 66 | }); 67 | 68 |      2 在显示的时候调用 69 | 70 | inputPayPwdDialog.show(); 71 | 72 |      3 获取密码 73 | 74 | inputPayPwdDialog.getPassword() 75 | 76 |       77 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/res/layout/paypwd_input_password_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 28 | 29 | 30 | 31 | 35 | 36 | 45 | 46 | 57 | 58 | 62 | 63 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/view/CEditTextSms.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.Gravity; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.example.weioule.inputkeyboarddemo.util.CountDown; 10 | import com.example.weioule.inputkeyboarddemo.R; 11 | 12 | 13 | /** 14 | * 发送验证码控件 15 | * author weioule 16 | * Created on 2018/3/6. 17 | */ 18 | public class CEditTextSms extends CEditText implements CountDown.OnCountDownListener { 19 | private TextView smsButton; 20 | private CountDown countDown; 21 | private SendSmsListener mSendSmsListener; 22 | private boolean externalStatus = true; //保存外部状态 23 | 24 | public CEditTextSms(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | initSmsButton(); 27 | initCountDown(); 28 | } 29 | 30 | private void initSmsButton() { 31 | smsButton = findViewById(R.id.right_iamge); 32 | smsButton.setVisibility(View.VISIBLE); 33 | smsButton.setTextAppearance(getContext(), R.style.font_red_fd6e5f_15); 34 | smsButton.setGravity(Gravity.CENTER); 35 | smsButton.setText("发送验证码"); 36 | smsButton.setOnClickListener(new OnClickListener() { 37 | 38 | @Override 39 | public void onClick(View paramView) { 40 | sendSms(); 41 | } 42 | }); 43 | } 44 | 45 | public void sendSms() { 46 | if (mSendSmsListener != null) { 47 | mSendSmsListener.onSendSms(); 48 | } 49 | } 50 | 51 | //短信发送成功 52 | public void onSendSms() { 53 | countDown.runTime(CountDown.INTER_S); 54 | } 55 | 56 | private void initCountDown() { 57 | countDown = new CountDown(60); 58 | countDown.setListener(this); 59 | } 60 | 61 | @Override 62 | public void onCountDownFinished() { 63 | setSmsEnable(externalStatus); 64 | } 65 | 66 | @Override 67 | public void onCountDownRun(int maxNum, int remainNum) { 68 | smsButton.setText("" + remainNum + "s后重发"); 69 | smsButton.setTextAppearance(getContext(), R.style.font_gray_9_15); 70 | smsButton.setEnabled(false); 71 | } 72 | 73 | public void setSendSmsListener(SendSmsListener mSendSmsListener) { 74 | this.mSendSmsListener = mSendSmsListener; 75 | } 76 | 77 | public void setSmsEnable(boolean isEnable) { 78 | externalStatus = isEnable; 79 | if (countDown.isRunning()) { 80 | return; 81 | } 82 | 83 | if (isEnable) { 84 | smsButton.setText("发送验证码"); 85 | smsButton.setTextAppearance(getContext(), R.style.font_red_fd6e5f_15); 86 | smsButton.setEnabled(true); 87 | } else { 88 | smsButton.setText("发送验证码"); 89 | smsButton.setTextAppearance(getContext(), R.style.font_red_fd6e5f_15); 90 | smsButton.setEnabled(false); 91 | } 92 | 93 | } 94 | 95 | public interface SendSmsListener { 96 | void onSendSms(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/util/CountDown.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.util; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import java.util.Timer; 7 | import java.util.TimerTask; 8 | 9 | public class CountDown { 10 | private static final int COUNT = 0000; 11 | private static final int FINISH = 0001; 12 | public static final int INTER_S = 1000; 13 | private int count; 14 | private int maxNum; 15 | private Timer timer; 16 | private TimerTask task; 17 | private OnCountDownListener listener; 18 | 19 | private Handler handler = new Handler() { 20 | @Override 21 | public synchronized void handleMessage(Message msg) { 22 | switch (msg.what) { 23 | case COUNT: 24 | if (listener != null) { 25 | listener.onCountDownRun(maxNum, maxNum - count); 26 | } 27 | break; 28 | case FINISH: 29 | if (listener != null) { 30 | listener.onCountDownFinished(); 31 | } 32 | break; 33 | default: 34 | break; 35 | } 36 | } 37 | }; 38 | 39 | public CountDown(int maxNum) { 40 | this.maxNum = maxNum; 41 | } 42 | 43 | public void runTime(int interval) { 44 | stopTime(); 45 | count = 0; 46 | timer = new Timer(true); 47 | task = new TimerTask() { 48 | @Override 49 | public void run() { 50 | count++; 51 | if (maxNum - count <= 0) { 52 | stopTime(); 53 | handler.sendEmptyMessage(FINISH); 54 | } else { 55 | handler.sendEmptyMessage(COUNT); 56 | } 57 | } 58 | }; 59 | timer.scheduleAtFixedRate(task, 100, interval); 60 | } 61 | 62 | public void runTime(int interval, int delay) { 63 | stopTime(); 64 | count = 0; 65 | timer = new Timer(true); 66 | task = new TimerTask() { 67 | @Override 68 | public void run() { 69 | count++; 70 | if (maxNum - count <= 0) { 71 | stopTime(); 72 | handler.sendEmptyMessage(FINISH); 73 | } else { 74 | handler.sendEmptyMessage(COUNT); 75 | } 76 | } 77 | }; 78 | timer.scheduleAtFixedRate(task, delay, interval); 79 | } 80 | 81 | public void stopTime() { 82 | if (task != null) { 83 | task.cancel(); 84 | task = null; 85 | } 86 | 87 | if (timer != null) { 88 | timer.cancel(); 89 | timer.purge(); 90 | timer = null; 91 | } 92 | } 93 | 94 | public boolean isRunning() { 95 | return timer != null && task != null; 96 | } 97 | 98 | public void setListener(OnCountDownListener listener) { 99 | this.listener = listener; 100 | } 101 | 102 | public interface OnCountDownListener { 103 | void onCountDownFinished(); 104 | 105 | void onCountDownRun(int maxNum, int remainNum); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 63 | 64 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 22 | 23 | 38 | 39 | 50 | 51 | 63 | 64 | 74 | 75 | 88 | 89 | 96 | 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/act/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.act; 2 | 3 | import android.content.Intent; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | import android.widget.Toast; 7 | 8 | import com.example.weioule.inputkeyboarddemo.R; 9 | import com.example.weioule.inputkeyboarddemo.keyboard.CumKeyboardContainer; 10 | import com.example.weioule.inputkeyboarddemo.util.IdCardUtil; 11 | import com.example.weioule.inputkeyboarddemo.view.CEditText; 12 | 13 | import java.util.Timer; 14 | import java.util.TimerTask; 15 | 16 | /** 17 | * Author by weioule. 18 | * Date on 2018/11/19. 19 | */ 20 | public class MainActivity extends BaseTitleActivity { 21 | 22 | protected static final String ID_INFO_BIRTHDAY = "id_info_birthday"; 23 | protected static final String ID_INFO_SEX = "id_info_sex"; 24 | protected CumKeyboardContainer mCustomKeyboardView; 25 | private boolean mBackKeyPressed = false; 26 | protected CEditText mIndentityCard; 27 | protected TextView mIdInfo, okBtn; 28 | 29 | @Override 30 | protected void initView() { 31 | addTitleText("实名认证"); 32 | mIndentityCard = findViewById(R.id.indentity_card); 33 | mIdInfo = findViewById(R.id.input_id_info); 34 | okBtn = findViewById(R.id.ok_button); 35 | 36 | mCustomKeyboardView = new CumKeyboardContainer(this, getInputType()); 37 | mCustomKeyboardView.attachKeyBoardView(); 38 | mIndentityCard.setCustomKeyboardView(mCustomKeyboardView); 39 | 40 | okBtn.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | clickBtn(); 44 | } 45 | }); 46 | findViewById(R.id.content).setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | hintKeyBoard(); 50 | } 51 | }); 52 | } 53 | 54 | protected void clickBtn() { 55 | IdCardUtil idCardUtil = new IdCardUtil(mIndentityCard.getText()); 56 | int correct = idCardUtil.isCorrect(); 57 | if (0 == correct) { 58 | Intent intent = new Intent(MainActivity.this, SecondActivity.class); 59 | intent.putExtra(ID_INFO_BIRTHDAY, idCardUtil.getBirthday()); 60 | intent.putExtra(ID_INFO_SEX, idCardUtil.getSex()); 61 | startActivity(intent); 62 | } else { 63 | mIndentityCard.showErrNote(idCardUtil.getErrMsg()); 64 | } 65 | } 66 | 67 | @Override 68 | protected void initData() { 69 | } 70 | 71 | @Override 72 | protected int getLayoutId() { 73 | return R.layout.activity_main; 74 | } 75 | 76 | protected boolean hintKeyBoard() { 77 | if (mCustomKeyboardView != null && mCustomKeyboardView.getVisibility() == View.VISIBLE) { 78 | mCustomKeyboardView.setCmbVisibility(View.GONE); 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | protected String getInputType() { 85 | return CumKeyboardContainer.IDCERT_TYPE; 86 | } 87 | 88 | @Override 89 | public void onBackPressed() { 90 | if (hintKeyBoard()) return; 91 | if (!mBackKeyPressed) { 92 | Toast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show(); 93 | mBackKeyPressed = true; 94 | new Timer().schedule(new TimerTask() {// 延时两秒,如果超出则取消取消上一次的记录 95 | 96 | @Override 97 | public void run() { 98 | mBackKeyPressed = false; 99 | } 100 | }, 2000); 101 | } else {// 退出程序 102 | this.finish(); 103 | System.exit(0); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/act/FindPayPwdActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.act; 2 | 3 | import android.text.TextUtils; 4 | import android.view.View; 5 | import android.view.inputmethod.EditorInfo; 6 | import android.widget.TextView; 7 | import android.widget.Toast; 8 | 9 | import com.example.weioule.inputkeyboarddemo.R; 10 | import com.example.weioule.inputkeyboarddemo.view.CEditText; 11 | import com.example.weioule.inputkeyboarddemo.view.CEditTextSms; 12 | 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | 17 | /** 18 | * author weioule 19 | * Created on 2018/3/6. 20 | */ 21 | public class FindPayPwdActivity extends BaseTitleActivity implements View.OnClickListener, CEditTextSms.SendSmsListener { 22 | 23 | private CEditTextSms mVerificationCode; 24 | private CEditText mEtphone; 25 | private TextView mSubmit; 26 | 27 | @Override 28 | protected void initView() { 29 | addTitleText("找回密码"); 30 | mEtphone = findViewById(R.id.et_phone); 31 | mVerificationCode = findViewById(R.id.et_verification_code); 32 | mVerificationCode.setIme(EditorInfo.IME_ACTION_DONE, ""); 33 | mVerificationCode.setSendSmsListener(this); 34 | mSubmit = findViewById(R.id.submit_btn); 35 | mSubmit.setOnClickListener(this); 36 | } 37 | 38 | @Override 39 | protected void initData() { 40 | } 41 | 42 | @Override 43 | protected int getLayoutId() { 44 | return R.layout.find_paypwd_activity; 45 | } 46 | 47 | @Override 48 | public void onClick(View v) { 49 | if (TextUtils.isEmpty(mVerificationCode.getText())) { 50 | mVerificationCode.showErrNote("验证码为空!"); 51 | } else if (checkSmsCode(mVerificationCode.getText())) { 52 | Toast.makeText(this, "密码找回成功", Toast.LENGTH_SHORT).show(); 53 | finish(); 54 | } else { 55 | mVerificationCode.showErrNote("验证码有误!"); 56 | } 57 | } 58 | 59 | @Override 60 | public void onSendSms() { 61 | if (TextUtils.isEmpty(mEtphone.getText())) { 62 | mEtphone.showErrNote("手机号为空!"); 63 | } else if (isMobileNO(mEtphone.getText())) { 64 | /**模拟发送验证码成功,开启倒计时*/ 65 | mVerificationCode.onSendSms(); 66 | } else { 67 | mEtphone.showErrNote("手机号不正确"); 68 | } 69 | } 70 | 71 | protected void onCheckButtonStatusChanged() { 72 | String verificationCode = mEtphone.getText().trim(); 73 | if (!TextUtils.isEmpty(verificationCode)) { 74 | mSubmit.setEnabled(true); 75 | } else { 76 | mSubmit.setEnabled(false); 77 | } 78 | } 79 | 80 | public static boolean isMobileNO(String mobileNums) { 81 | /** 82 | * 判断字符串是否符合手机号码格式 83 | * 移动号段: 134,135,136,137,138,139,147,150,151,152,157,158,159,170,178,182,183,184,187,188 84 | * 联通号段: 130,131,132,145,155,156,170,171,175,176,185,186 85 | * 电信号段: 133,149,153,170,173,177,180,181,189 86 | * @param str 87 | * @return 待检测的字符串 88 | */ 89 | // "[1]"代表下一位为数字可以是几,"[0-9]"代表可以为0-9中的一个,"[5,7,9]"表示可以是5,7,9中的任意一位,[^4]表示除4以外的任何一个,\\d{9}"代表后面是可以是0~9的数字,有9位。 90 | String telRegex = "^((13[0-9])|(14[5,7,9])|(15[^4])|(18[0-9])|(17[0,1,3,5,6,7,8]))\\d{8}$"; 91 | if (TextUtils.isEmpty(mobileNums)) 92 | return false; 93 | else 94 | return mobileNums.matches(telRegex); 95 | } 96 | 97 | /** 98 | * 验证验证码 99 | * 100 | * @param smsCode 101 | * @return 102 | */ 103 | public static boolean checkSmsCode(String smsCode) { 104 | if (smsCode == null || "".equals(smsCode)) { 105 | return false; 106 | } 107 | Pattern p = Pattern.compile("^([0-9]{6})$");// ^([0-9]{6})$,^\\d{6,8} 108 | Matcher m = p.matcher(smsCode); 109 | return m.matches(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/weioule/inputkeyboarddemo/view/CmbEditText.java: -------------------------------------------------------------------------------- 1 | package com.example.weioule.inputkeyboarddemo.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.text.InputType; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | import android.view.inputmethod.InputMethodManager; 12 | import android.widget.EditText; 13 | 14 | import com.example.weioule.inputkeyboarddemo.keyboard.CumKeyboardContainer; 15 | 16 | import java.lang.reflect.InvocationTargetException; 17 | import java.lang.reflect.Method; 18 | 19 | 20 | /** 21 | * Author by weioule. 22 | * Date on 2018/11/19. 23 | */ 24 | @SuppressLint("AppCompatCustomView") 25 | public class CmbEditText extends EditText implements View.OnFocusChangeListener, View.OnTouchListener { 26 | private CumKeyboardContainer mCmbView; 27 | private boolean mIsCustomKeyboardEnable = false; 28 | 29 | public CmbEditText(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | } 32 | 33 | public void setCustomKeyboardEnable(boolean isCustomKeyboardEnable) { 34 | mIsCustomKeyboardEnable = isCustomKeyboardEnable; 35 | 36 | if (mIsCustomKeyboardEnable) { 37 | noRelateIM(); 38 | 39 | this.setOnFocusChangeListener(this); 40 | this.setOnTouchListener(this); 41 | } 42 | } 43 | 44 | public void setCmbView(CumKeyboardContainer cmbView) { 45 | if (!mIsCustomKeyboardEnable) { 46 | return; 47 | } 48 | mCmbView = cmbView; 49 | } 50 | 51 | public void showCMBKeyboardWindow() { 52 | if (mIsCustomKeyboardEnable) { 53 | //显示自定义键盘 54 | hideIM(); 55 | setFocusable(true); 56 | requestFocus(); 57 | setCursorVisible(true); 58 | 59 | mCmbView.setEditText(this); 60 | mCmbView.setCmbVisibility(View.VISIBLE); 61 | } else { 62 | //显示系统键盘 63 | setFocusable(true); 64 | setFocusableInTouchMode(true); 65 | requestFocus(); 66 | InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 67 | inputManager.showSoftInput(this, 0); 68 | } 69 | } 70 | 71 | @Override 72 | public void onFocusChange(View v, boolean hasFocus) { 73 | if (!hasFocus) { 74 | closeCMBKeyboardWindow(); 75 | } 76 | } 77 | 78 | @Override 79 | public boolean onTouch(View v, MotionEvent event) { 80 | showCMBKeyboardWindow(); 81 | return false; 82 | } 83 | 84 | private void closeCMBKeyboardWindow() { 85 | 86 | } 87 | 88 | private void hideIM() { 89 | if (getWindowToken() != null) { 90 | InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 91 | imm.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); 92 | } 93 | } 94 | 95 | private void noRelateIM() { 96 | ((Activity) getContext()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); 97 | 98 | int currentVersion = android.os.Build.VERSION.SDK_INT; 99 | String methodName = null; 100 | if (currentVersion >= 16) { 101 | // 4.2 102 | methodName = "setShowSoftInputOnFocus"; 103 | } else if (currentVersion >= 14) { 104 | // 4.0 105 | methodName = "setSoftInputShownOnFocus"; 106 | } 107 | 108 | if (methodName == null) { 109 | this.setInputType(InputType.TYPE_NULL); 110 | } else { 111 | Class cls = EditText.class; 112 | Method setShowSoftInputOnFocus; 113 | try { 114 | setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class); 115 | setShowSoftInputOnFocus.setAccessible(true); 116 | setShowSoftInputOnFocus.invoke(this, false); 117 | } catch (NoSuchMethodException e) { 118 | this.setInputType(InputType.TYPE_NULL); 119 | e.printStackTrace(); 120 | } catch (IllegalAccessException e) { 121 | // TODO Auto-generated catch block 122 | e.printStackTrace(); 123 | } catch (IllegalArgumentException e) { 124 | // TODO Auto-generated catch block 125 | e.printStackTrace(); 126 | } catch (InvocationTargetException e) { 127 | // TODO Auto-generated catch block 128 | e.printStackTrace(); 129 | } 130 | } 131 | } 132 | 133 | @Override 134 | protected void onDetachedFromWindow() { 135 | super.onDetachedFromWindow(); 136 | mCmbView = null; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/res/layout/c_edit_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 24 | 25 |