性能优化之APK瘦身,EditText输入金额类型

作者: 新金沙平台  发布:2019-09-08

editText默认的属性里面是没有金额类型的,所以要实现这个功能我们就必须自己动手丰衣足食。

好久没有写Android的文章了,有两三个月多了吧,刚开始搞微信小程序,后来又开搞ReactNative,现在又兴奋的开搞AI机器学习的东西,感觉挺有意思的,不过AI与其它的东西相比要难很多,需要补很多数学知识,不过我现在学的都还是皮毛,没啥深度,但是我会慢慢深入的,对AI的兴趣比较大,年轻人就要不断的折腾嘛,当然自己的老本行也要搞起啦,饭还是要吃的。

参考:

一.EditText只允许输入数字、小数点。

首先要知道金额有两部分构成,整数部分和小数部分,要实现只输入数字和小数点很简单。自己查能很容易查到。

把type设置成InputType.TYPE_NUMBER_FLAG_DECIMAL|InputType.TYPE_CLASS_NUMBER就行

那这样做有个缺点,小数部分可以有很多位。而我们知道金额类型的小数部分只能有两位,所以这个方法不合适。

好像说的有点多了,今天的这篇文章是介绍Android中自定义键盘的一些套路,通过定义一个数字键盘为例,本篇的文章语言是基于Kotlin实现的,如果还没有用或者不熟悉该语言的同学,可以自己补习,我之前也写过入门文章。

  • 《Android高级进阶》第24章
  • [Android技术专题]APK瘦身看这一篇文章就够了
  • Android 瘦身实践
  • Android APP终极瘦身指南

二.设置字符过滤

网上有很多文章都是这样写。

mEdit.setFilters(new InputFilter[]{new InputFilter() { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { if(source.equals && dest.toString().length{ return "0."; } if(dest.toString().contains{ int index = dest.toString().indexOf; int mlength = dest.toString().substring.length(); if(mlength == 3){ return ""; } } return null; }}});

这样的做法能实现是能实现,但是这样的写法没有考虑到很多种会出现的情况,也就是说只是这样写的话,在某些情况下的用户体验很不好。

图片 1效果图

三.设置监听addTextChangedListener

上面的第二种方法你可以在里边加自己的算法来处理特殊情况,但是我不太喜欢这个方法,直到我看到一个哥们用addTextChangedListener来实现。我才发现,用addTextChangedListener来做金额类型的输入挺合适的。虽然也是要自己写算法去解决特殊情况下的问题,但是用起来比第二种方法舒服。

我先贴代码再做解释。

public class EditTextUtils { /** * 设置edittext只能输入小数点后两位 */ public static void afterDotTwo(final EditText editText) { editText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // 限制最多能输入9位整数 if (s.toString().contains { if (s.toString().indexOf > 9) { s = s.toString().subSequence   s.toString().substring(s.toString().indexOf; editText.setText; editText.setSelection; } }else { if (s.toString().length{ s = s.toString().subSequence; editText.setText; editText.setSelection; } } // 判断小数点后只能输入两位 if (s.toString().contains { if (s.length() - 1 - s.toString().indexOf > 2) { s = s.toString().subSequence(0, s.toString().indexOf; editText.setText; editText.setSelection(s.length; } } //如果第一个数字为0,第二个不为点,就不允许输入 if (s.toString().startsWith && s.toString.length { if (!s.toString().substring.equals { editText.setText(s.subSequence; editText.setSelection; return; } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { if (editText.getText().toString != null && !editText.getText().toString.equals { if (editText.getText().toString.substring.equals { editText.setText("0"   editText.getText().toString; editText.setSelection; } } } }); }}

我先把我工具类中的其它方法屏蔽调,只留这个方法。你会看到算法的代码量不算稍微有点杂。这是我参考那哥们写的再加上自己碰到的特殊需求改进的。当然每个人都应该根据自己的需求去写不同的算法。但是至少先要掌握两点:addTextChangedListener的了解和Java String字符串的一些基本操作。

源码传送门

  • 省流量
  • 给用户一个好印象
1. 限制整数只能输入多位

我这边的需求是整数最多为9位数,所以我先判断是否有小数点,有的话就获取前面9位加上小数点以及其后所有。

 if (s.toString().contains { if (s.toString().indexOf > 9) { s = s.toString().subSequence   s.toString().substring(s.toString().indexOf; editText.setText; editText.setSelection; } }else { if (s.toString().length{ s = s.toString().subSequence; editText.setText; editText.setSelection; } }

我们下面的介绍都是依靠上图的实现来展开的,首先是软键盘的布局,我们需要我们的res/xml目录下创建一个xml文件,根节点就是Keyboard,然后就是键盘的每一行Row,每一行中可以指定每一列,也就是具体的键Key,代码实现

2. 限制小数点后只能输两位

这个判断是判断金额的重点,本来金额小数点后就只能有两位,当然有些人的需求可能是只能有一位,这不要紧,把数字改下就行。首先判断是否有小数点,如果有,判断是否小数点后大于两位,如果大于就只取前两位。

 if (s.toString().contains { if (s.length() - 1 - s.toString().indexOf > 2) { s = s.toString().subSequence(0, s.toString().indexOf; editText.setText; editText.setSelection(s.length; } }
<?xml version="1.0" encoding="utf-8"?><!--isRepeatable:长按时是否重复这个操作--><Keyboard xmlns:andro android:horizontalGap="1px" android:keyHeight="7%p" android:keyWidth="33.33%p" android:verticalGap="1px"> <Row android:keyHeight="6%p"> <Key android:codes="-4" android:keyIcon="@drawable/hidden" android:keyWidth="100%" /> </Row> <Row> <Key android:codes="49" android:keyLabel="1" /> <Key android:codes="50" android:keyLabel="2" /> <Key android:codes="51" android:keyLabel="3" /> </Row> <Row> <Key android:codes="52" android:keyLabel="4" /> <Key android:codes="53" android:keyLabel="5" /> <Key android:codes="54" android:keyLabel="6" /> </Row> <Row> <Key android:codes="55" android:keyLabel="7" /> <Key android:codes="56" android:keyLabel="8" /> <Key android:codes="57" android:keyLabel="9" /> </Row> <Row> <Key android:codes="46" android:keyLabel="." /> <Key android:codes="48" android:keyLabel="0" /> <Key android:codes="-5" android:isRepeatable="true" android:keyIcon="@drawable/delete" /> </Row></Keyboard>
  • Android系统碎片化严重,为了适配,每个APP要支持的主流dpi分类会很多,dpi越多,那么就相当于资源文件变多,也许一个图标,我们要给它对应的ldpi,mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi等都要弄一张图标文件
  • Android生态系统的不断发展成熟,出现了许多方便开发者的函数库和SDK,库或SDK引入过多,不可避免的引入很多重复功能代码和资源文件。
3.第一个数为0的情况

我这里写的判断不是很好,之后可以改进。这个特殊情况是这样的,假如你输入的第一位是0,你想想,你能输入0233,05这种数字吗,就是您能,这样展示给用户的效果也很不友好,所以要判断如果第一位数是0,第二位不是小数点的话,就输出0。

 if (s.toString().startsWith && s.toString.length { if (!s.toString().substring.equals { editText.setText(s.subSequence; editText.setSelection; return; } }

上面也说了这步的算法有两个问题,第一,如果在0.26的情况下,我把光标点在0后面,输入一个不为0的数字假设5,得到的结果是0而不是5.26。第二,假如还是0.26的情况下,我把光标点在小数点后面,删除小数点,得到的不是26而是0。所以这步的算法有些问题。那为什么不现在改呢,不好意思,最近太忙,写文章都很赶。

在Keyboard节点属性中,我们通过horizontalGap设置水平的间距,通过verticalGap设置垂直的间距,通过keyWidth设置每一个key的宽度,通过keyHeight设置。需要注意的地点是如果Keyboard ,Row和Key都可以指定宽高。通常我们可以指定在Keyboard 中设置每一个键的宽高就可以了。当然如果对特定行的宽高要有所调整,可以在Row 或者key上设置,例如我们示例图中展示的最上面的一行,它的宽度比其它行都低了一点,则我们在第一行设置了属性android:keyHeight="6%p"

图片 2apk解压后的目录

4.第一个是小数点的情况

假如你的数是5.26,这时候你把光标放到5后面,删除5,如果你不做处理,那展示出来的就是.26,这样的展示就很不友好,所以我们要想办法要在第一位为小数点的情况下补0。

 public void afterTextChanged(Editable s) { if (editText.getText().toString != null && !editText.getText().toString.equals { if (editText.getText().toString.substring.equals { editText.setText("0"   editText.getText().toString; editText.setSelection; } } }

这里写在afterTextChanged里面,所以让大家先要了解addTextChangedListener再来看算法,写在afterTextChanged里面是因为我要在“之后”做操作。算法也很简单,判断有字符串并且第一位为小数点的情况下,添加个0在前面。

在每一个key中有下面常用属性

  • AndroidManifest.xml:系统清单文件
  • assets:存放用来需要打包到Android应用程序的静态资源文件,例如图片资源文件,json配置文件,渠道配置文件,二进制数据文件
  • classes.dex:应用程序的可执行文件,可以通过反编译工具反编译后进行查看,如果APP的方法数超过65K的限制,需要进行分包,这样就会存在多个dex文件。
  • lib:存放程序依赖的不同ABI类型的.so文件
  • res:存放应用的资源文件,包括图片资源,字符串资源,颜色资源,尺寸资源等,这些资源都会出现在资源清单文件R.java的索引中
因为这个算法是很赶的情况下写的,很多地方也许可以合并,可能也有一些特殊的情况没有考虑到,最好不要直接拿来用,我只是举个栗子说明addTextChangedListener能很好的实现这个功能,具体要怎么实现还需要根据个人自己的需求和特殊情况去写算法。
  • android:codes 官网介绍是说这个是该键的unicode 值或者逗号分隔值,当然我们也可以设置成我们想要的值,在源码中提供了几个特定的值

图片 3res目录g

四.最方便的方法

没错,要实现这个功能的最方便方法就是......跪求谷歌在下一个版本添加一个MONEY类型的TYPE,这样就是一行代码的事情了,呵呵。

  • resources.arsc:资源索引表,用来描述具有ID值的资源的配置信息
  • META-INF:存放签名相关的信息,用于验证APK包的完整性以及保证系统的安全,主要包含三个文件
    • MANIFEST.MF:主要存放APK包中每个文件的名字及每个文件的SHA1哈希值
//就不解释了,通过名字应该看得出来 public static final int KEYCODE_SHIFT = -1; public static final int KEYCODE_MODE_CHANGE = -2; public static final int KEYCODE_CANCEL = -3; public static final int KEYCODE_DONE = -4; public static final int KEYCODE_DELETE = -5; public static final int KEYCODE_ALT = -6;

图片 4MANIFEST.MF

  • android:keyOutputText 设置该值后,当点击key时回调onText(text: CharSequence?)会执行,参数就是我们设置的值。
  • android:keyIcon设置key上显示的icon
  • android:keyLabel 键上显示的值
  • android:isRepeatable 当长按时是否重复该键设置的操作,例如我们删除键可以设置此属性。
  • android:keyEdgeFlags 该属性有两个值,分别是left,right,用与指定显示在最左还是最右,一般不用此属性。默认从左到右排列。还有其它属性,不在介绍,可以自己去查阅api
  • CERT.SF:通常每个APP会有一个特定的名字,例如BDMOBILE.SF,NETDISK_.SF等,它保存的是MANIFEST.MF的哈希值以及MANIFEST.MF文件中每一个哈希项的哈希值
  • CERT.RSA:保存了apk包的签名和证书的公钥信息

该类是用来渲染虚拟键盘的类,类中有一个接口OnKeyboardActionListener能检测按键和触摸动作,我们要自定义虚拟键盘,只需要继承该类并实现该监听接口即可,当然我这里并没有实现接口,我单独创建了一个工具类,用于将自定义键盘View和EditText关联,并设置接口监听,这些稍后介绍到再说,我们最主要关注的就是onDraw方法,它可以让我们自定义键盘的绘制,随心所欲的画我们想要的东西。当然,我们也可以不做任何实现,它默认的有一种绘制。

从中可以分析出,一个APK包中的组成中,对APK大小影响较大的文件分别是

class CustomKeyboardView : KeyboardView { private var mKeyBoard: Keyboard? = null constructor(context: Context, attrs: AttributeSet) : this(context, attrs,0) {} constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { // } override fun onDraw(canvas: Canvas) { super.onDraw mKeyBoard = this.keyboard var keys: MutableList<Keyboard.Key>? = null if (mKeyBoard != null) { keys = mKeyBoard!!.keys } if (keys != null) { for (key in keys) { //可以自定义自己的绘制(例如某个按钮绘制背景图片和文字,亦或者更改某个按钮颜色等) if (key.codes[0] == -111) {//过滤指定某个键自定义绘制 } } } }}
  • Java代码文件:classs*.dex
  • Native代码文件:.so文件
  • 资源文件:包括assets文件,res目录以及resources.arsc索引文件

本文由新金沙平台发布于新金沙平台,转载请注明出处:性能优化之APK瘦身,EditText输入金额类型

关键词: 新金沙平台 js55