Repository: maning0303/MNPasswordEditText
Branch: master
Commit: 4db5ab1316af
Files: 39
Total size: 59.2 KB
Directory structure:
gitextract_ktc04v1x/
├── .gitignore
├── .idea/
│ ├── caches/
│ │ ├── build_file_checksums.ser
│ │ └── gradle_models.ser
│ ├── codeStyles/
│ │ └── Project.xml
│ ├── compiler.xml
│ ├── copyright/
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── inspectionProfiles/
│ │ └── Project_Default.xml
│ ├── jarRepositories.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── vcs.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── maning/
│ │ └── mnpasswordedittext/
│ │ └── MainActivity.java
│ └── res/
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── values-w820dp/
│ └── dimens.xml
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── pswedittextlibrary/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── maning/
│ │ └── pswedittextlibrary/
│ │ └── MNPasswordEditText.java
│ └── res/
│ └── values/
│ ├── attr.xml
│ └── strings.xml
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
================================================
FILE: .idea/codeStyles/Project.xml
================================================
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>
================================================
FILE: .idea/compiler.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>
================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
<component name="CopyrightManager">
<settings default="" />
</component>
================================================
FILE: .idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
================================================
FILE: .idea/gradle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/pswedittextlibrary" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
================================================
FILE: .idea/inspectionProfiles/Project_Default.xml
================================================
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
<option name="TOP_LEVEL_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="INNER_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="METHOD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
</value>
</option>
<option name="FIELD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="IGNORE_DEPRECATED" value="false" />
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
<option name="myAdditionalJavadocTags" value="date" />
</inspection_tool>
</profile>
</component>
================================================
FILE: .idea/jarRepositories.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="$USER_HOME$/Develop/Android/android_sdk/extras/android/m2repository" />
<option name="name" value="$USER_HOME$/Develop/Android/android_sdk/extras/android/m2repository" />
<option name="url" value="file:$USER_HOME$/Develop/Android/android_sdk/extras/android/m2repository/" />
</remote-repository>
<remote-repository>
<option name="id" value="$USER_HOME$/Develop/Android/android_sdk/extras/google/m2repository" />
<option name="name" value="$USER_HOME$/Develop/Android/android_sdk/extras/google/m2repository" />
<option name="url" value="file:$USER_HOME$/Develop/Android/android_sdk/extras/google/m2repository/" />
</remote-repository>
<remote-repository>
<option name="id" value="$USER_HOME$/Develop/Android/android_sdk/extras/m2repository" />
<option name="name" value="$USER_HOME$/Develop/Android/android_sdk/extras/m2repository" />
<option name="url" value="file:$USER_HOME$/Develop/Android/android_sdk/extras/m2repository/" />
</remote-repository>
</component>
</project>
================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ASMIdeaPluginConfiguration">
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="ASMPluginConfiguration">
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/layout/activity_main.xml" value="0.10612968591691996" />
</map>
</option>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="13">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="4" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="10" class="java.lang.String" itemvalue="android.annotation.Nullable" />
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
<item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="12">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="9" class="java.lang.String" itemvalue="android.annotation.NonNull" />
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
<item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MNPasswordEditText.iml" filepath="$PROJECT_DIR$/MNPasswordEditText.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/MNPasswordEditText.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/MNPasswordEditText.app.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/pswedittextlibrary/MNPasswordEditText.pswedittextlibrary.iml" filepath="$PROJECT_DIR$/.idea/modules/pswedittextlibrary/MNPasswordEditText.pswedittextlibrary.iml" />
</modules>
</component>
</project>
================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
================================================
FILE: README.md
================================================
# MNPasswordEditText [](https://jitpack.io/#maning0303/MNPasswordEditText)
Android验证码和密码输入框,能自定义输入框个数和样式(连体,下划线和方形框)
类似微信支付宝的密码输入框等
## 截图:


## 如何添加
### 1:Gradle添加:
#### 1.在Project的build.gradle中添加仓库地址
``` gradle
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
```
#### 2.在app目录下的build.gradle中添加依赖
``` gradle
dependencies {
implementation 'com.github.maning0303:MNPasswordEditText:V1.0.4'
}
```
### 2:源码Module添加:
#### 直接关联pswedittextlibrary
``` gradle
implementation project(':pswedittextlibrary')
```
## 使用方法(查看Demo详情):
### 1:自定义参数介绍:
``` java
<declare-styleable name="MNPasswordEditText">
<!--密码框的颜色-->
<attr name="psw_border_color" format="color" />
<!--密码框选中的颜色-->
<attr name="psw_border_selected_color" format="color" />
<!--密码文字的颜色,圆形密码颜色-->
<attr name="psw_text_color" format="color" />
<!--密码框的圆角-->
<attr name="psw_border_radius" format="dimension" />
<!--密码框的线的大小-->
<attr name="psw_border_width" format="dimension" />
<!--密码框的每个间隔,只有样式2才起作用-->
<attr name="psw_item_margin" format="dimension" />
<!--密码框背景色-->
<attr name="psw_background_color" format="color" />
<!--密码框输入的模式:4.明文,3.文字,2.图片,1.圆形-->
<attr name="psw_mode" format="enum">
<!--圆形默认-->
<enum name="Circle" value="1" />
<!--图片-->
<enum name="Bitmap" value="2" />
<!--文本-->
<enum name="Text" value="3" />
<!--原始-->
<enum name="OriginalText" value="4" />
</attr>
<!--密码框样式: 1.连在一起 2.分开单独显示 3.下划线形式-->
<attr name="psw_style" format="enum">
<!--连在一起-->
<enum name="StyleDefault" value="1" />
<!--单独-->
<enum name="StyleOneself" value="2" />
<!--下划线形式-->
<enum name="StyleUnderLine" value="3" />
</attr>
<!--密码文字遮盖-->
<attr name="psw_cover_text" format="string" />
<!--密码图片遮盖-->
<attr name="psw_cover_bitmap_id" format="reference" />
<!--密码圆形遮盖颜色-->
<attr name="psw_cover_circle_color" format="color" />
<!--密码圆形遮盖半径-->
<attr name="psw_cover_circle_radius" format="dimension" />
<!--密码图片遮盖长宽-->
<attr name="psw_cover_bitmap_width" format="dimension" />
<!--是否显示光标-->
<attr name="psw_show_cursor" format="boolean" />
<!--光标颜色-->
<attr name="psw_cursor_color" format="color" />
<!--光标高度-->
<attr name="psw_cursor_height" format="dimension" />
<!--光标宽度-->
<attr name="psw_cursor_width" format="dimension" />
<!--光标圆角-->
<attr name="psw_cursor_corner_radius" format="dimension" />
</declare-styleable>
```
### 2:布局文件使用(详细查看Demo):
``` java
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="6"
android:textSize="20sp"
app:psw_border_color="#267eb4"
app:psw_border_radius="4dp"
app:psw_border_selected_color="#dc10a2"
app:psw_border_width="2dp"
app:psw_cover_text="密"
app:psw_cursor_width="10dp"
app:psw_item_margin="10dp"
app:psw_mode="Text"
app:psw_show_cursor="true"
app:psw_style="StyleOneself"
app:psw_text_color="#393939" /
```
### 2:代码相关:
``` java
mPswEditText = (MNPasswordEditText) findViewById(R.id.mPswEditText);
//监听输入的过程
mPswEditText.setOnTextChangeListener(new MNPasswordEditText.OnTextChangeListener() {
@Override
public void onTextChange(String text, boolean isComplete) {
tvShow.setText(text);
if (isComplete) {
Toast.makeText(MainActivity.this, "输入完成", Toast.LENGTH_SHORT).show();
}
}
});
```
## 其他详情请查看Demo
## 版本记录:
v1.0.4:
1.新增光标显示
2.自定义属性名称调整
## 推荐:
Name | Describe |
--- | --- |
[GankMM](https://github.com/maning0303/GankMM) | (Material Design & MVP & Retrofit + OKHttp & RecyclerView ...)Gank.io Android客户端:每天一张美女图片,一个视频短片,若干Android,iOS等程序干货,周一到周五每天更新,数据全部由 干货集中营 提供,持续更新。 |
[MNUpdateAPK](https://github.com/maning0303/MNUpdateAPK) | Android APK 版本更新的下载和安装 |
[MNImageBrowser](https://github.com/maning0303/MNImageBrowser) | 交互特效的图片浏览框架,微信向下滑动动态关闭 |
[MClearEditText](https://github.com/maning0303/MClearEditText) | 带有删除功能的EditText |
[MNPasswordEditText](https://github.com/maning0303/MNPasswordEditText) | 类似微信支付宝的密码输入框。 |
[MNCrashMonitor](https://github.com/maning0303/MNCrashMonitor) | Debug监听程序崩溃日志,展示崩溃日志列表,方便自己平时调试。 |
[MNProgressHUD](https://github.com/maning0303/MNProgressHUD) | MNProgressHUD是对常用的自定义弹框封装,加载ProgressDialog,状态显示的StatusDialog和自定义Toast,支持背景颜色,圆角,边框和文字的自定义。 |
[MNZXingCode](https://github.com/maning0303/MNZXingCode) | 快速集成二维码扫描和生成二维码 |
[MNMLKitScanner](https://github.com/maning0303/MNMLKitScanner) | 基于Google ML Kit 快速集成二维码扫描 |
[MNChangeSkin](https://github.com/maning0303/MNChangeSkin) | Android夜间模式,通过Theme实现 |
[MNVideoPlayer](https://github.com/maning0303/MNVideoPlayer) | SurfaceView + MediaPlayer 实现的视频播放器,支持横竖屏切换,手势快进快退、调节音量,亮度等。------代码简单,新手可以看一看。 |
[SwitcherView](https://github.com/maning0303/SwitcherView) | 垂直滚动的广告栏文字展示。 |
[MNCalendar](https://github.com/maning0303/MNCalendar) | 简单的日历控件练习,水平方向日历支持手势滑动切换,跳转月份;垂直方向日历选取区间范围。 |
[MNSwipeToLoadDemo](https://github.com/maning0303/MNSwipeToLoadDemo) | 利用SwipeToLoadLayout实现的各种下拉刷新效果(饿了吗,京东,百度外卖,美团外卖,天猫下拉刷新等)。 |
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.maning.mnpasswordedittext"
minSdkVersion 14
targetSdkVersion 28
versionCode 104
versionName "1.0.4"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
//测试Gradle
// implementation 'com.github.maning0303:MNPasswordEditText:V1.0.4'
implementation project(':pswedittextlibrary')
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/maning/Develop/Android/SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.maning.mnpasswordedittext">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app/src/main/java/com/maning/mnpasswordedittext/MainActivity.java
================================================
package com.maning.mnpasswordedittext;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
import com.maning.pswedittextlibrary.MNPasswordEditText;
public class MainActivity extends AppCompatActivity {
private MNPasswordEditText mPswEditText;
private TextView tvShow;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvShow = (TextView) findViewById(R.id.tvShow);
mPswEditText = (MNPasswordEditText) findViewById(R.id.mPswEditText);
mPswEditText.setOnTextChangeListener(new MNPasswordEditText.OnTextChangeListener() {
@Override
public void onTextChange(String text, boolean isComplete) {
tvShow.setText(text);
if (isComplete) {
Toast.makeText(MainActivity.this, "输入完成", Toast.LENGTH_SHORT).show();
}
}
});
}
}
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvShow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:id="@+id/mPswEditText"
android:layout_width="300dp"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="6"
android:textSize="20sp"
app:psw_cover_circle_color="@color/colorPrimaryDark"
app:psw_cover_circle_radius="12dp"
app:psw_show_cursor="true" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="6"
android:textSize="20sp"
app:psw_border_color="#c9c9c9"
app:psw_border_selected_color="#FF0000"
app:psw_border_width="2dp"
app:psw_cover_text="码"
app:psw_item_margin="20dp"
app:psw_mode="Text"
app:psw_show_cursor="false"
app:psw_style="StyleUnderLine"
app:psw_text_color="#393939" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="5"
android:textSize="20sp"
app:psw_background_color="#cfcfcf"
app:psw_border_color="#3D5AFE"
app:psw_border_radius="100dp"
app:psw_border_selected_color="#46c4b1"
app:psw_border_width="1dp"
app:psw_cursor_color="#FF9900"
app:psw_cursor_corner_radius="4dp"
app:psw_cursor_height="20dp"
app:psw_cursor_width="2dp"
app:psw_item_margin="20dp"
app:psw_mode="OriginalText"
app:psw_show_cursor="true"
app:psw_style="StyleOneself"
app:psw_text_color="#FFFFFF" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="4"
android:textSize="20sp"
app:psw_background_color="#FFFFFF"
app:psw_border_color="#7e7e7e"
app:psw_border_radius="10dp"
app:psw_border_selected_color="#dcce10"
app:psw_border_width="2dp"
app:psw_cover_bitmap_id="@mipmap/ic_launcher"
app:psw_cover_bitmap_width="30dp"
app:psw_cursor_corner_radius="4dp"
app:psw_cursor_height="20dp"
app:psw_cursor_width="2dp"
app:psw_item_margin="40dp"
app:psw_mode="Bitmap"
app:psw_show_cursor="true"
app:psw_style="StyleOneself"
app:psw_text_color="#393939" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="6"
android:textSize="20sp"
app:psw_border_color="#267eb4"
app:psw_border_radius="4dp"
app:psw_border_selected_color="#dc10a2"
app:psw_border_width="2dp"
app:psw_cover_text="密"
app:psw_cursor_width="10dp"
app:psw_item_margin="10dp"
app:psw_mode="Text"
app:psw_show_cursor="true"
app:psw_style="StyleOneself"
app:psw_text_color="#393939" />
<com.maning.pswedittextlibrary.MNPasswordEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:inputType="number"
android:maxLength="9"
android:textSize="20sp"
app:psw_border_color="#FF9800"
app:psw_border_radius="4dp"
app:psw_border_selected_color="#8BC34A"
app:psw_border_width="2dp"
app:psw_cover_circle_color="#8BC34A"
app:psw_cover_circle_radius="10dp"
app:psw_item_margin="10dp"
app:psw_mode="Circle"
app:psw_style="StyleOneself"
app:psw_text_color="#393939" />
</LinearLayout>
</ScrollView>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">MNPasswordEditText</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: pswedittextlibrary/.gitignore
================================================
/build
================================================
FILE: pswedittextlibrary/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
group='com.github.maning0303'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
compileOnly 'androidx.legacy:legacy-support-v4:1.0.0'
compileOnly 'androidx.annotation:annotation:1.2.0'
}
================================================
FILE: pswedittextlibrary/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/maning/Develop/Android/SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: pswedittextlibrary/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.maning.pswedittextlibrary">
<application android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
>
</application>
</manifest>
================================================
FILE: pswedittextlibrary/src/main/java/com/maning/pswedittextlibrary/MNPasswordEditText.java
================================================
package com.maning.pswedittextlibrary;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.text.InputFilter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import java.lang.reflect.Field;
/**
* @author : maning
* @desc : 验证码和密码的输入框
*/
public class MNPasswordEditText extends EditText {
private static final String TAG = "MNPasswordEditText";
private Context mContext;
private String defaultColor = "#FF0000";
/**
* 长度
*/
private int maxLength;
/**
* 文字的颜色
*/
private int textColor;
/**
* 文字的画笔
*/
private Paint mPaintText;
/**
* 线框的画笔
*/
private Paint mPaintLine;
/**
* 背景色
*/
private int backgroundColor;
/**
* 线框的颜色
*/
private int borderColor;
/**
* 线框被选中的颜色
*/
private int borderSelectedColor;
/**
* 线框的圆角
*/
private float borderRadius;
/**
* 线框的宽度
*/
private float borderWidth;
/**
* 密码框的间隔
*/
private float itemMargin;
/**
* 输入的类型
*/
private int inputMode;
/**
* 样式
*/
private int editTextStyle;
/**
* 文字遮盖
*/
private String coverText;
/**
* 图片遮盖
*/
private int coverBitmapID;
/**
* 图片宽度
*/
private float coverBitmapWidth;
/**
* 圆形遮盖的颜色
*/
private int coverCirclrColor;
/**
* 圆形遮盖的半径
*/
private float coverCirclrRadius;
/**
* 线框背景
*/
private GradientDrawable gradientDrawable = new GradientDrawable();
private Bitmap coverBitmap;
private Paint mPaintCursor;
/**
* 光标
*/
private GradientDrawable cursorDrawable = new GradientDrawable();
private int cursorColor;
private float cursorWidth;
private float cursorHeight;
private float cursorCornerRadius;
private boolean showCursor = false;
private boolean mCursorFlag;
private Blink mBlink;
public MNPasswordEditText(Context context) {
this(context, null);
}
public MNPasswordEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MNPasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
//初始化参数
initAttrs(attrs, defStyleAttr);
//初始化相关
init();
}
private void initAttrs(AttributeSet attrs, int defStyleAttr) {
TypedArray array = mContext.obtainStyledAttributes(attrs, R.styleable.MNPasswordEditText, defStyleAttr, 0);
//背景色
backgroundColor = array.getColor(R.styleable.MNPasswordEditText_psw_background_color, Color.parseColor("#FFFFFF"));
//边框颜色
borderColor = array.getColor(R.styleable.MNPasswordEditText_psw_border_color, Color.parseColor(defaultColor));
//边框选中的颜色
borderSelectedColor = array.getColor(R.styleable.MNPasswordEditText_psw_border_selected_color, Color.parseColor(defaultColor));
//文字的颜色
textColor = array.getColor(R.styleable.MNPasswordEditText_psw_text_color, Color.parseColor(defaultColor));
//边框圆角
borderRadius = array.getDimension(R.styleable.MNPasswordEditText_psw_border_radius, dip2px(6));
//边框线大小
borderWidth = array.getDimension(R.styleable.MNPasswordEditText_psw_border_width, dip2px(1));
//每个密码框的间隔
itemMargin = array.getDimension(R.styleable.MNPasswordEditText_psw_item_margin, dip2px(10));
//输入的模式
inputMode = array.getInt(R.styleable.MNPasswordEditText_psw_mode, 1);
//整体样式
editTextStyle = array.getInt(R.styleable.MNPasswordEditText_psw_style, 1);
//替换的图片
coverBitmapID = array.getResourceId(R.styleable.MNPasswordEditText_psw_cover_bitmap_id, -1);
//替换的文字
coverText = array.getString(R.styleable.MNPasswordEditText_psw_cover_text);
if (TextUtils.isEmpty(coverText)) {
coverText = "密";
}
//圆形的颜色
coverCirclrColor = array.getColor(R.styleable.MNPasswordEditText_psw_cover_circle_color, Color.parseColor(defaultColor));
//密码圆形遮盖半径
coverCirclrRadius = array.getDimension(R.styleable.MNPasswordEditText_psw_cover_circle_radius, 0);
//密码图片遮盖长宽
coverBitmapWidth = array.getDimension(R.styleable.MNPasswordEditText_psw_cover_bitmap_width, 0);
//--------------光标属性-----
showCursor = array.getBoolean(R.styleable.MNPasswordEditText_psw_show_cursor, false);
cursorColor = array.getColor(R.styleable.MNPasswordEditText_psw_cursor_color, borderSelectedColor);
cursorHeight = array.getDimension(R.styleable.MNPasswordEditText_psw_cursor_height, 0);
cursorWidth = array.getDimension(R.styleable.MNPasswordEditText_psw_cursor_width, 6);
cursorCornerRadius = array.getDimension(R.styleable.MNPasswordEditText_psw_cursor_corner_radius, 0);
//回收
array.recycle();
}
private void init() {
//最大的长度
maxLength = getMaxLength();
//隐藏光标
setCursorVisible(false);
//设置本来文字的颜色为透明
setTextColor(Color.TRANSPARENT);
//触摸获取焦点
setFocusableInTouchMode(true);
//屏蔽长按
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return true;
}
});
//初始化画笔
//文字
mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintText.setStyle(Paint.Style.FILL);
mPaintText.setColor(textColor);
mPaintText.setTextSize(getTextSize());
//线
mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setColor(borderColor);
mPaintLine.setStrokeWidth(borderWidth);
//光标
cursorDrawable.setCornerRadius(cursorCornerRadius);
cursorDrawable.setColor(cursorColor);
mPaintCursor = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintCursor.setStyle(Paint.Style.FILL);
mPaintCursor.setColor(cursorColor);
//遮盖是图片方式,提前加载图片
if (inputMode == 2) {
//判断有没有图片
if (coverBitmapID == -1) {
//抛出异常
throw new NullPointerException("遮盖图片为空");
} else {
coverBitmap = BitmapFactory.decodeResource(getContext().getResources(), coverBitmapID);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取宽高
int measuredWidth = getMeasuredWidth();
float itemH = getMeasuredHeight();
//方形框
float margin = itemMargin;
float itemW = (measuredWidth - margin * (maxLength - 1)) / maxLength;
int currentIndex = getText().length();
//判断类型
if (editTextStyle == 1) {
//连体框
gradientDrawable.setStroke((int) borderWidth, borderColor);
gradientDrawable.setCornerRadius(borderRadius);
gradientDrawable.setColor(backgroundColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
//Android系统大于等于API16,使用setBackground
setBackground(gradientDrawable);
} else {
//Android系统小于API16,使用setBackgroundDrawable
setBackgroundDrawable(gradientDrawable);
}
margin = 0;
itemW = measuredWidth / maxLength;
//画线
for (int i = 1; i < maxLength; i++) {
float startX = itemW * i;
float startY = 0;
float stopX = startX;
float stopY = itemH;
canvas.drawLine(startX, startY, stopX, stopY, mPaintLine);
}
} else if (editTextStyle == 2) {
gradientDrawable.setStroke((int) borderWidth, borderColor);
gradientDrawable.setCornerRadius(borderRadius);
gradientDrawable.setColor(backgroundColor);
Bitmap bitmap = drawableToBitmap(gradientDrawable, (int) itemW, (int) itemH);
Bitmap bitmapSelected = null;
if (borderSelectedColor != 0) {
gradientDrawable.setStroke((int) borderWidth, borderSelectedColor);
bitmapSelected = drawableToBitmap(gradientDrawable, (int) itemW, (int) itemH);
}
//画每个Item背景
for (int i = 0; i < maxLength; i++) {
float left = itemW * i + margin * i;
float top = 0;
if (bitmapSelected == null) {
canvas.drawBitmap(bitmap, left, top, mPaintLine);
} else {
if (currentIndex == i) {
//选中是另外的颜色
canvas.drawBitmap(bitmapSelected, left, top, mPaintLine);
} else {
canvas.drawBitmap(bitmap, left, top, mPaintLine);
}
}
}
} else if (editTextStyle == 3) {
//下划线格式
for (int i = 0; i < maxLength; i++) {
if (borderSelectedColor != 0) {
if (currentIndex == i) {
//选中是另外的颜色
mPaintLine.setColor(borderSelectedColor);
} else {
mPaintLine.setColor(borderColor);
}
} else {
mPaintLine.setColor(borderColor);
}
float startX = itemW * i + itemMargin * i;
float startY = itemH - borderWidth;
float stopX = startX + itemW;
float stopY = startY;
canvas.drawLine(startX, startY, stopX, stopY, mPaintLine);
}
}
//写文字
String currentText = getText().toString();
for (int i = 0; i < maxLength; i++) {
if (!TextUtils.isEmpty(currentText) && i < currentText.length()) {
//<!--密码框输入的模式:1.圆形,2.图片,3.文字,4.明文-->
if (inputMode == 1) {
//圆点半径
float circleRadius = itemW * 0.5f * 0.5f;
if (circleRadius > itemH / 2f) {
circleRadius = itemH * 0.5f * 0.5f;
}
if (coverCirclrRadius > 0) {
circleRadius = coverCirclrRadius;
}
float startX = (itemW / 2f) + itemW * i + margin * i;
float startY = (itemH) / 2.0f;
mPaintText.setColor(coverCirclrColor);
canvas.drawCircle(startX, startY, circleRadius, mPaintText);
} else if (inputMode == 2) {
float picW = itemW * 0.5f;
if (coverBitmapWidth > 0) {
picW = coverBitmapWidth;
}
float startX = (itemW - picW) / 2f + itemW * i + margin * i;
float startY = (itemH - picW) / 2f;
Bitmap bitmap = Bitmap.createScaledBitmap(coverBitmap, (int) picW, (int) picW, true);
canvas.drawBitmap(bitmap, startX, startY, mPaintText);
} else if (inputMode == 3) {
float fontWidth = getFontWidth(mPaintText, coverText);
float fontHeight = getFontHeight(mPaintText, coverText);
float startX = (itemW - fontWidth) / 2f + itemW * i + margin * i;
float startY = (itemH + fontHeight) / 2f - 6;
mPaintText.setColor(textColor);
canvas.drawText(coverText, startX, startY, mPaintText);
} else {
String StrPosition = String.valueOf(currentText.charAt(i));
float fontWidth = getFontWidth(mPaintText, StrPosition);
float fontHeight = getFontHeight(mPaintText, StrPosition);
float startX = (itemW - fontWidth) / 2f + itemW * i + margin * i;
float startY = (itemH + fontHeight) / 2f;
mPaintText.setColor(textColor);
canvas.drawText(StrPosition, startX, startY, mPaintText);
}
}
}
if (showCursor && mCursorFlag) {
if (cursorHeight == 0 || cursorHeight > itemH) {
cursorHeight = itemH * 50 / 100;
}
Bitmap bitmap = drawableToBitmap(cursorDrawable, (int) cursorWidth, (int) cursorHeight);
float cursorLeft = (itemW + margin) * currentIndex + itemW / 2 - cursorWidth / 2;
float cursorTop = (itemH - cursorHeight) / 2;
canvas.drawBitmap(bitmap, cursorLeft, cursorTop, mPaintCursor);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
resumeBlink();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
suspendBlink();
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
if (mBlink != null) {
mBlink.uncancel();
}
makeBlink();
} else {
if (mBlink != null) {
mBlink.cancel();
}
}
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) {
if (mBlink != null) {
mBlink.uncancel();
}
makeBlink();
} else {
if (mBlink != null) {
mBlink.cancel();
}
}
}
private void resumeBlink() {
if (mBlink != null) {
mBlink.uncancel();
}
makeBlink();
}
private void suspendBlink() {
if (mBlink != null) {
mBlink.cancel();
}
}
private void makeBlink() {
if (true) {
if (mBlink == null) mBlink = new Blink();
removeCallbacks(mBlink);
postDelayed(mBlink, 500);
} else {
if (mBlink != null) removeCallbacks(mBlink);
}
}
private class Blink implements Runnable {
private boolean mCancelled = false;
@Override
public void run() {
mCursorFlag = !mCursorFlag;
invalidate();
if (mCancelled) {
return;
}
//每个500毫秒刷新一次
postDelayed(this, 500);
}
public void cancel() {
if (!mCancelled) {
removeCallbacks(this);
mCancelled = true;
}
}
public void uncancel() {
mCancelled = false;
}
}
public static Bitmap drawableToBitmap(Drawable drawable, int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(
width,
height,
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
return bitmap;
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
//刷新界面
invalidate();
if (onTextChangeListener != null) {
if (getText().toString().length() == getMaxLength()) {
onTextChangeListener.onTextChange(getText().toString(), true);
} else {
onTextChangeListener.onTextChange(getText().toString(), false);
}
}
}
public float getFontWidth(Paint paint, String str) {
Rect rect = new Rect();
paint.getTextBounds(str, 0, str.length(), rect);
return rect.width();
}
public float getFontHeight(Paint paint, String str) {
Rect rect = new Rect();
paint.getTextBounds(str, 0, str.length(), rect);
return rect.height();
}
public int getMaxLength() {
int length = 0;
try {
InputFilter[] inputFilters = getFilters();
for (InputFilter filter : inputFilters) {
Class<?> c = filter.getClass();
if (c.getName().equals("android.text.InputFilter$LengthFilter")) {
Field[] f = c.getDeclaredFields();
for (Field field : f) {
if (field.getName().equals("mMax")) {
field.setAccessible(true);
length = (Integer) field.get(filter);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return length;
}
private int dip2px(float dpValue) {
final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private OnTextChangeListener onTextChangeListener;
public void setOnTextChangeListener(OnTextChangeListener onTextChangeListener) {
this.onTextChangeListener = onTextChangeListener;
}
public interface OnTextChangeListener {
/**
* 监听输入变化
*
* @param text 当前的文案
* @param isComplete 是不是完成输入
*/
void onTextChange(String text, boolean isComplete);
}
}
================================================
FILE: pswedittextlibrary/src/main/res/values/attr.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MNPasswordEditText">
<!--密码框的颜色-->
<attr name="psw_border_color" format="color" />
<!--密码框选中的颜色-->
<attr name="psw_border_selected_color" format="color" />
<!--密码文字的颜色,圆形密码颜色-->
<attr name="psw_text_color" format="color" />
<!--密码框的圆角-->
<attr name="psw_border_radius" format="dimension" />
<!--密码框的线的大小-->
<attr name="psw_border_width" format="dimension" />
<!--密码框的每个间隔,只有样式2才起作用-->
<attr name="psw_item_margin" format="dimension" />
<!--密码框背景色-->
<attr name="psw_background_color" format="color" />
<!--密码框输入的模式:4.明文,3.文字,2.图片,1.圆形-->
<attr name="psw_mode" format="enum">
<!--圆形默认-->
<enum name="Circle" value="1" />
<!--图片-->
<enum name="Bitmap" value="2" />
<!--文本-->
<enum name="Text" value="3" />
<!--原始-->
<enum name="OriginalText" value="4" />
</attr>
<!--密码框样式: 1.连在一起 2.分开单独显示 3.下划线形式-->
<attr name="psw_style" format="enum">
<!--连在一起-->
<enum name="StyleDefault" value="1" />
<!--单独-->
<enum name="StyleOneself" value="2" />
<!--下划线形式-->
<enum name="StyleUnderLine" value="3" />
</attr>
<!--密码文字遮盖-->
<attr name="psw_cover_text" format="string" />
<!--密码图片遮盖-->
<attr name="psw_cover_bitmap_id" format="reference" />
<!--密码圆形遮盖颜色-->
<attr name="psw_cover_circle_color" format="color" />
<!--密码圆形遮盖半径-->
<attr name="psw_cover_circle_radius" format="dimension" />
<!--密码图片遮盖长宽-->
<attr name="psw_cover_bitmap_width" format="dimension" />
<!--是否显示光标-->
<attr name="psw_show_cursor" format="boolean" />
<!--光标颜色-->
<attr name="psw_cursor_color" format="color" />
<!--光标高度-->
<attr name="psw_cursor_height" format="dimension" />
<!--光标宽度-->
<attr name="psw_cursor_width" format="dimension" />
<!--光标圆角-->
<attr name="psw_cursor_corner_radius" format="dimension" />
</declare-styleable>
</resources>
================================================
FILE: pswedittextlibrary/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">PswEditTextLibrary</string>
</resources>
================================================
FILE: settings.gradle
================================================
include ':app', ':pswedittextlibrary'
gitextract_ktc04v1x/ ├── .gitignore ├── .idea/ │ ├── caches/ │ │ ├── build_file_checksums.ser │ │ └── gradle_models.ser │ ├── codeStyles/ │ │ └── Project.xml │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── inspectionProfiles/ │ │ └── Project_Default.xml │ ├── jarRepositories.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── maning/ │ │ └── mnpasswordedittext/ │ │ └── MainActivity.java │ └── res/ │ ├── layout/ │ │ └── activity_main.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── values-w820dp/ │ └── dimens.xml ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── pswedittextlibrary/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── maning/ │ │ └── pswedittextlibrary/ │ │ └── MNPasswordEditText.java │ └── res/ │ └── values/ │ ├── attr.xml │ └── strings.xml └── settings.gradle
SYMBOL INDEX (29 symbols across 2 files)
FILE: app/src/main/java/com/maning/mnpasswordedittext/MainActivity.java
class MainActivity (line 10) | public class MainActivity extends AppCompatActivity {
method onCreate (line 15) | @Override
FILE: pswedittextlibrary/src/main/java/com/maning/pswedittextlibrary/MNPasswordEditText.java
class MNPasswordEditText (line 27) | public class MNPasswordEditText extends EditText {
method MNPasswordEditText (line 122) | public MNPasswordEditText(Context context) {
method MNPasswordEditText (line 126) | public MNPasswordEditText(Context context, AttributeSet attrs) {
method MNPasswordEditText (line 130) | public MNPasswordEditText(Context context, AttributeSet attrs, int def...
method initAttrs (line 141) | private void initAttrs(AttributeSet attrs, int defStyleAttr) {
method init (line 187) | private void init() {
method onDraw (line 237) | @Override
method onAttachedToWindow (line 377) | @Override
method onDetachedFromWindow (line 383) | @Override
method onWindowFocusChanged (line 389) | @Override
method onFocusChanged (line 404) | @Override
method resumeBlink (line 419) | private void resumeBlink() {
method suspendBlink (line 426) | private void suspendBlink() {
method makeBlink (line 432) | private void makeBlink() {
class Blink (line 443) | private class Blink implements Runnable {
method run (line 447) | @Override
method cancel (line 458) | public void cancel() {
method uncancel (line 465) | public void uncancel() {
method drawableToBitmap (line 471) | public static Bitmap drawableToBitmap(Drawable drawable, int width, in...
method onTextChanged (line 483) | @Override
method getFontWidth (line 497) | public float getFontWidth(Paint paint, String str) {
method getFontHeight (line 503) | public float getFontHeight(Paint paint, String str) {
method getMaxLength (line 509) | public int getMaxLength() {
method dip2px (line 531) | private int dip2px(float dpValue) {
method setOnTextChangeListener (line 538) | public void setOnTextChangeListener(OnTextChangeListener onTextChangeL...
type OnTextChangeListener (line 542) | public interface OnTextChangeListener {
method onTextChange (line 549) | void onTextChange(String text, boolean isComplete);
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (68K chars).
[
{
"path": ".gitignore",
"chars": 118,
"preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
},
{
"path": ".idea/codeStyles/Project.xml",
"chars": 3309,
"preview": "<component name=\"ProjectCodeStyleConfiguration\">\n <code_scheme name=\"Project\" version=\"173\">\n <codeStyleSettings lan"
},
{
"path": ".idea/compiler.xml",
"chars": 170,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"CompilerConfiguration\">\n <bytecodeTar"
},
{
"path": ".idea/copyright/profiles_settings.xml",
"chars": 74,
"preview": "<component name=\"CopyrightManager\">\n <settings default=\"\" />\n</component>"
},
{
"path": ".idea/encodings.xml",
"chars": 159,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"Encoding\">\n <file url=\"PROJECT\" chars"
},
{
"path": ".idea/gradle.xml",
"chars": 810,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"GradleMigrationSettings\" migrationVersio"
},
{
"path": ".idea/inspectionProfiles/Project_Default.xml",
"chars": 1444,
"preview": "<component name=\"InspectionProjectProfileManager\">\n <profile version=\"1.0\">\n <option name=\"myName\" value=\"Project De"
},
{
"path": ".idea/jarRepositories.xml",
"chars": 2314,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"RemoteRepositoriesConfiguration\">\n <r"
},
{
"path": ".idea/misc.xml",
"chars": 4045,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ASMIdeaPluginConfiguration\">\n <asm sk"
},
{
"path": ".idea/modules.xml",
"chars": 662,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ProjectModuleManager\">\n <modules>\n "
},
{
"path": ".idea/vcs.xml",
"chars": 180,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "README.md",
"chars": 6007,
"preview": "# MNPasswordEditText [](https://jitpack.io/#maning0303/MNPass"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 847,
"preview": "apply plugin: 'com.android.application'\n\nandroid {\n compileSdkVersion 29\n defaultConfig {\n applicationId \"c"
},
{
"path": "app/proguard-rules.pro",
"chars": 664,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 673,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n pa"
},
{
"path": "app/src/main/java/com/maning/mnpasswordedittext/MainActivity.java",
"chars": 1064,
"preview": "package com.maning.mnpasswordedittext;\n\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimpor"
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 5510,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 208,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#3F51B5</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/dimens.xml",
"chars": 211,
"preview": "<resources>\n <!-- Default screen margins, per the Android Design guidelines. -->\n <dimen name=\"activity_horizontal"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 81,
"preview": "<resources>\n <string name=\"app_name\">MNPasswordEditText</string>\n</resources>\n"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 383,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
},
{
"path": "app/src/main/res/values-w820dp/dimens.xml",
"chars": 358,
"preview": "<resources>\n <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n (such as s"
},
{
"path": "build.gradle",
"chars": 691,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n r"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 232,
"preview": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 783,
"preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2404,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
},
{
"path": "pswedittextlibrary/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "pswedittextlibrary/build.gradle",
"chars": 655,
"preview": "apply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\n\ngroup='com.github.maning0303'\n\na"
},
{
"path": "pswedittextlibrary/proguard-rules.pro",
"chars": 664,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
},
{
"path": "pswedittextlibrary/src/main/AndroidManifest.xml",
"chars": 298,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.maning.pswedittextlibrary\">\n"
},
{
"path": "pswedittextlibrary/src/main/java/com/maning/pswedittextlibrary/MNPasswordEditText.java",
"chars": 18195,
"preview": "package com.maning.pswedittextlibrary;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport an"
},
{
"path": "pswedittextlibrary/src/main/res/values/attr.xml",
"chars": 2281,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <declare-styleable name=\"MNPasswordEditText\">\n <!--密码框的颜色"
},
{
"path": "pswedittextlibrary/src/main/res/values/strings.xml",
"chars": 81,
"preview": "<resources>\n <string name=\"app_name\">PswEditTextLibrary</string>\n</resources>\n"
},
{
"path": "settings.gradle",
"chars": 38,
"preview": "include ':app', ':pswedittextlibrary'\n"
}
]
// ... and 3 more files (download for full content)
About this extraction
This page contains the full source code of the maning0303/MNPasswordEditText GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (59.2 KB), approximately 16.6k tokens, and a symbol index with 29 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.