├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── layout │ │ │ ├── activity_main.xml │ │ │ ├── activity_custom_style.xml │ │ │ └── activity_simple.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ └── com │ │ │ └── lwjfork │ │ │ └── example │ │ │ ├── style │ │ │ ├── CustomTextDrawer.java │ │ │ └── CustomeBlockDrawer.java │ │ │ ├── MainActivity.java │ │ │ ├── SimpleActivity.java │ │ │ └── CustomStyleActivity.java │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── library ├── .gitignore ├── src │ └── main │ │ ├── res │ │ └── values │ │ │ ├── strings.xml │ │ │ └── attrs.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── lwjfork │ │ └── code │ │ ├── text │ │ ├── NoneTextDrawer.java │ │ ├── PasswordTextDrawer.java │ │ ├── TextDrawer.java │ │ └── BaseTextDrawer.java │ │ ├── style │ │ ├── CodeInputType.java │ │ └── BlockShape.java │ │ ├── cusor │ │ ├── CursorDrawable.java │ │ └── CursorDrawer.java │ │ ├── block │ │ ├── NoneBlockDrawer.java │ │ ├── StrokeBlockDrawer.java │ │ ├── SolidBlockDrawer.java │ │ ├── UnderlineBlockDrawer.java │ │ └── BaseBlockDrawer.java │ │ ├── base │ │ └── BaseDrawer.java │ │ └── CodeEditText.java ├── gradle.properties ├── proguard-rules.pro └── build.gradle ├── example.jpg ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── .gitignore ├── gradle.properties ├── .github └── workflows │ └── android.yml ├── README.md ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/example.jpg -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CodeEditText 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | library 3 | 4 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | def submoduleProject = project(':library') 3 | submoduleProject.name = 'CodeEditText' -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwjfork/CodeEditText/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed May 13 13:42:37 CST 2020 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-6.5-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/text/NoneTextDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.text; 2 | 3 | import android.graphics.Rect; 4 | 5 | /** 6 | * Created by lwj on 2019/1/12. 7 | * lwjfork@gmail.com 8 | * 什么都不绘制 9 | */ 10 | public class NoneTextDrawer extends BaseTextDrawer { 11 | 12 | 13 | public NoneTextDrawer(int codeInputType, int codeTextColor, int codeTextSize, int dotRadius) { 14 | super(codeInputType, codeTextColor, codeTextSize, dotRadius); 15 | } 16 | 17 | @Override 18 | protected void drawText(Rect rect, char c) { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/text/PasswordTextDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.text; 2 | 3 | import android.graphics.Rect; 4 | 5 | /** 6 | * Created by lwj on 2019/1/12. 7 | * lwjfork@gmail.com 8 | * 密文绘制 9 | */ 10 | public class PasswordTextDrawer extends BaseTextDrawer { 11 | 12 | 13 | public PasswordTextDrawer(int codeInputType, int codeTextColor, int codeTextSize, int dotRadius) { 14 | super(codeInputType, codeTextColor, codeTextSize, dotRadius); 15 | } 16 | 17 | @Override 18 | protected void drawText(Rect rect, char c) { 19 | canvas.drawCircle(rect.centerX(), rect.centerY(), dotRadius, textPaint); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings 5 | .checkstyle 6 | 7 | # IntelliJ IDEA 8 | .idea 9 | *.iml 10 | 11 | *.ipr 12 | *.iws 13 | classes 14 | gen-external-apklibs 15 | *.class 16 | out/ 17 | 18 | # Gradle 19 | .gradle 20 | #gradle 21 | /.idea/workspace.xml 22 | /.idea/libraries/* 23 | build 24 | 25 | # Maven 26 | target 27 | release.properties 28 | pom.xml.* 29 | 30 | # Ant 31 | bin 32 | gen 33 | build.xml 34 | ant.properties 35 | local.properties 36 | proguard.cfg 37 | proguard-project.txt 38 | /local.properties 39 | 40 | # Other 41 | tmp 42 | .DS_Store 43 | *.hprof 44 | 45 | # custom 46 | /apks 47 | *.apk 48 | app/mirror 49 | 50 | # Android 51 | *.li 52 | *.log 53 | captures 54 | /mapping*.txt 55 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/style/CodeInputType.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.style; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | import static com.lwjfork.code.style.CodeInputType.NONE; 9 | import static com.lwjfork.code.style.CodeInputType.PASSWORD; 10 | import static com.lwjfork.code.style.CodeInputType.TEXT; 11 | 12 | /** 13 | * Created by lwj on 2019/1/17. 14 | * lwjfork@gmail.com 15 | */ 16 | @Retention(RetentionPolicy.SOURCE) 17 | @IntDef({PASSWORD, TEXT, NONE}) 18 | public @interface CodeInputType { 19 | int PASSWORD = 1; // 密码样式 20 | int TEXT = 2; // 明文 21 | int NONE = -1; // 什么都不画 22 | } 23 | -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | PUBLISH_GROUP_ID=io.github.lwjfork 2 | PUBLISH_ARTIFACT_ID=CodeEditText 3 | PUBLISH_VERSION=1.0.7 4 | 5 | # pom 6 | POM_NAME=CodeEditText 7 | POM_DESCRIPTION=CodeEditText 8 | POM_URL=https://github.com/lwjfork/CodeEditText 9 | ## pom.scm 10 | POM_SCM_CONNECTION=scm:git@github.com:lwjfork/CodeEditText.git 11 | POM_SCM_DEV_CONNECTION=scm:git@github.com:lwjfork/CodeEditText.git 12 | POM_SCM_URL=https://github.com/lwjfork/CodeEditText.git 13 | 14 | ## pom.licenses 15 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 16 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 17 | 18 | ## pom.developers 19 | POM_DEVELOPER_ID=lwjfork 20 | POM_DEVELOPER_NAME=lwjfork 21 | POM_DEVELOPER_EMAIL=lwjfork@gmail.com 22 | 23 | PROJECT_NAME=CodeEditText 24 | 25 | 26 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/cusor/CursorDrawable.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.cusor; 2 | 3 | import android.graphics.drawable.ShapeDrawable; 4 | 5 | /** 6 | * Created by lwj on 2019/1/12. 7 | * lwjfork@gmail.com 8 | * 光标 9 | */ 10 | public class CursorDrawable extends ShapeDrawable { 11 | private int mHeight; 12 | 13 | public CursorDrawable(int cursorColor, int cursorWidth, int cursorHeight) { 14 | mHeight = cursorHeight; 15 | setDither(false); 16 | getPaint().setColor(cursorColor); 17 | setIntrinsicWidth(cursorWidth); 18 | } 19 | 20 | public void setBounds(int paramInt1, int paramInt2, int paramInt3, int paramInt4) { 21 | super.setBounds(paramInt1, paramInt2, paramInt3, this.mHeight + paramInt2); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /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 | DEFAULT_GRADLE_VERSION=3.1.2 15 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/style/BlockShape.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.style; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | import static com.lwjfork.code.style.BlockShape.NONE; 9 | import static com.lwjfork.code.style.BlockShape.SOLID; 10 | import static com.lwjfork.code.style.BlockShape.STROKE; 11 | import static com.lwjfork.code.style.BlockShape.UNDERLINE; 12 | 13 | /** 14 | * Created by lwj on 2019/1/17. 15 | * lwjfork@gmail.com 16 | */ 17 | @Retention(RetentionPolicy.SOURCE) 18 | @IntDef({STROKE, SOLID, UNDERLINE, NONE}) 19 | public @interface BlockShape { 20 | int STROKE = 1; // 边框 21 | int SOLID = 2; // 填充 22 | int UNDERLINE = 3; // 下划线 23 | int NONE = -1; // 什么都不画 24 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/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 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/block/NoneBlockDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.block; 2 | 3 | import android.graphics.RectF; 4 | 5 | /** 6 | * Created by lwj on 2019/1/12. 7 | * lwjfork@gmail.com 8 | * 任性,就是什么都不画 9 | */ 10 | public class NoneBlockDrawer extends BaseBlockDrawer { 11 | 12 | public NoneBlockDrawer(int blockNormalColor, int blockFocusedColor, int blockErrorColor, int blockShape, int blockLineWidth, int blockCorner) { 13 | super(blockNormalColor, blockFocusedColor, blockErrorColor, blockShape, blockLineWidth, blockCorner); 14 | } 15 | 16 | @Override 17 | protected void drawFocusedBlock(RectF rectF) { 18 | 19 | } 20 | 21 | @Override 22 | protected void drawNormalBlock(RectF rectF) { 23 | 24 | } 25 | 26 | @Override 27 | protected void drawErrorBlock(RectF rectF) { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/block/StrokeBlockDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.block; 2 | 3 | import android.graphics.Paint; 4 | 5 | /** 6 | * Created by lwj on 2019/1/12. 7 | * lwjfork@gmail.com 8 | * 边框绘制者 9 | */ 10 | public class StrokeBlockDrawer extends SolidBlockDrawer { 11 | 12 | 13 | public StrokeBlockDrawer() { 14 | super(); 15 | } 16 | 17 | 18 | public StrokeBlockDrawer(int blockNormalColor, int blockFocusedColor, int blockErrorColor, int blockShape, int blockLineWidth, int blockCorner) { 19 | super(blockNormalColor, blockFocusedColor, blockErrorColor, blockShape, blockLineWidth, blockCorner); 20 | } 21 | 22 | @Override 23 | protected void initPaint() { 24 | super.initPaint(); 25 | blockPaint.setStyle(Paint.Style.STROKE); 26 | blockPaint.setStrokeWidth(blockLineWidth); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lwjfork/example/style/CustomTextDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.example.style; 2 | 3 | import android.graphics.Paint; 4 | import android.graphics.Rect; 5 | 6 | import com.lwjfork.code.text.BaseTextDrawer; 7 | 8 | /** 9 | * Created by lwj on 2019/1/17. 10 | * lwjfork@gmail.com 11 | */ 12 | public class CustomTextDrawer extends BaseTextDrawer { 13 | 14 | private int textBaseLineY; 15 | 16 | public CustomTextDrawer() { 17 | super(); 18 | } 19 | 20 | @Override 21 | protected void drawText(Rect rect, char c) { 22 | Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); 23 | float top = fontMetrics.top;// 基线到字体上边框的距离 24 | float bottom = fontMetrics.bottom;// 基线到字体下边框的距离 25 | textBaseLineY = (int) (rect.centerY() - top / 2 - bottom / 2); 26 | canvas.drawText("X", rect.centerX(), textBaseLineY, textPaint); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | def SLVersion = rootProject.ext.supportLibVersion 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | buildToolsVersion rootProject.ext.buildToolsVersion 6 | 7 | 8 | defaultConfig { 9 | minSdkVersion rootProject.ext.minSdkVersion 10 | targetSdkVersion rootProject.ext.targetSdkVersion 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | lintOptions { 24 | abortOnError false 25 | } 26 | 27 | } 28 | 29 | 30 | dependencies { 31 | implementation fileTree(include: ['*.jar'], dir: 'libs') 32 | implementation "com.android.support:appcompat-v7:$SLVersion" 33 | implementation 'io.github.lwjfork:CodeEditText:1.0.5' 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/lwjfork/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.example; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.View; 6 | 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_main); 14 | 15 | findViewById(R.id.btn_simple).setOnClickListener(new View.OnClickListener() { 16 | @Override 17 | public void onClick(View v) { 18 | SimpleActivity.launch(MainActivity.this); 19 | } 20 | }); 21 | findViewById(R.id.btn_custom_style).setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | CustomStyleActivity.launch(MainActivity.this); 25 | } 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /library/src/main/java/com/lwjfork/code/text/TextDrawer.java: -------------------------------------------------------------------------------- 1 | package com.lwjfork.code.text; 2 | 3 | import android.graphics.Paint; 4 | import android.graphics.Rect; 5 | 6 | import com.lwjfork.code.style.CodeInputType; 7 | 8 | /** 9 | * Created by lwj on 2019/1/12. 10 | * lwjfork@gmail.com 11 | * 明文绘制 12 | */ 13 | public class TextDrawer extends BaseTextDrawer { 14 | private int textBaseLineY; 15 | public TextDrawer(@CodeInputType int codeInputType, int codeTextColor, int codeTextSize, int dotRadius) { 16 | super(codeInputType, codeTextColor, codeTextSize, dotRadius); 17 | } 18 | 19 | @Override 20 | protected void drawText(Rect rect, char c) { 21 | Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); 22 | float top = fontMetrics.top;// 基线到字体上边框的距离 23 | float bottom = fontMetrics.bottom;// 基线到字体下边框的距离 24 | textBaseLineY = (int) (rect.centerY() - top / 2 - bottom / 2); 25 | canvas.drawText(c + "", rect.centerX(), textBaseLineY, textPaint); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 15 | 16 |