在日常开发中,常常因为不同项目需求的共性,同时也是考虑到用户使用方式的共性,会有许多复用性极高的代码实现,这里特地总结一下。
有图有真相##
如上图,这些都是日常开发中及常见APP中会遇到的样式,有些看似简单,实现起来却较为费劲;有些很常用,这里只是提供一种思路,如果你有好意见,更好的实现方式,可以在评论中反馈哦!
这里就按照图中所示,从上到下依次展开来说
文本相关##
- 杠掉价(价格中间带一条划掉的横向)
这个在购物类APP中算是常见的内容了,实现方式如下
/**
* 实现TextView 中间横线效果
*/
marketPrice.getPaint()
.setFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
- 价格精确到分
数字精确到分,其实从任何一种语言来说,都有很多实现方式,有很多自带的API可以参考。这里就从java语言来说两种实现方式
/**
* 实现小数点后保留两位
*/
String valueStr = "88.8888";
double valueDou = 88.8888;
Price1.setText(ShoppingTools.FormatNum2(valueStr));
Price2.setText(ShoppingTools.FormatNum2(valueDou));
这里的Price1 和 Price2 分别是上图中的88.88 和88.89,细心的你可能会说,为什么两种不一样。这里我们可以看一下ShoppingTools类中的这两个重载的静态方法:
/**
* 截取小数点后两位,而不是四舍五入
*
* @param number
* @return
*/
public static String FormatNum2(String number) {
String intNumber;
if (number.contains(".")) {
int dot_index = number.indexOf(".");
System.err.println("the dot index is " + dot_index);
try {
intNumber = number.substring(0, dot_index + 3);
} catch (Exception e) {
intNumber = number + "0";
}
System.out.println(intNumber);
} else {
System.out.println(number);
intNumber = number + ".00";
}
return intNumber;
}
/**
* 小数点后保留两位
*/
public static String FormatNum2(double f) {
BigDecimal bd = new BigDecimal(f);
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
System.err.println("------------" + bd);
return bd.toString();
}
这两个重载的方法,分别就不同的入参做了小数点后保留两位的操作,注意,这里不是简单的四舍五入,有时候四舍五入总有一方是要吃亏的。这里,对于double类型的数据,暂时没有想到可以直接截取两位小数,不四舍五入的方法,做过的同学可以分享一下。
- 简单的富文本
对于上面这种文本变色的UI,就暂且叫做简单的富文本吧。
这种UI,最笨的办法就是几个不同颜色TextView拼接起来。可能做一两个你觉得无所谓,但是如果有需求需要你实现很多个这样的拼接组合,你是不是想和产品聊聊呢。而且作为一名程序猿,怎么可以这样呢?一定有什么高大上的方法。方法的确是有,而且还不少。这里就选两种最常用的说说。
/**
* 实现TextView文本内变色
*/
SpannableStringBuilder builder = new SpannableStringBuilder(richStyleTv.getText().toString());
ForegroundColorSpan redSpan = new ForegroundColorSpan(Color.RED);
ForegroundColorSpan greenSpan = new ForegroundColorSpan(Color.GREEN);
builder.setSpan(redSpan, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(greenSpan, 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
richStyleTv.setText(builder);
好了,这么长一大段代码,就实现了上图中第一行的变色文本。你可能觉得,写这么多,就实现那么一行,还是不够高大上呀。好了,下面就是简单的写法
richStyleTv1.setText(Html.fromHtml("第<font color=green>二</font>杯半价,第<font color=green>三</font>杯免费"));
这种写法很简短,而且还能很方便的设置字体。但如你所见,也有个很明显的缺点,文本内容不可以动态修改,这一点上第一种写法代码虽多,却没有限制。关于SpannableStringBuilder,其实还有很多用法,这里的用法只是冰山一角,有兴趣的你可以去好好研究一番。
交互体验##
- 密码可见与否
这个可以说是最常用的用户体验,登录、注册时都会用到。
实现也是很简单:
/**
* 密码明文显示或密文显示
*/
show.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//明文显示
passwordEdit.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
} else {
passwordEdit.setTransformationMethod(PasswordTransformationMethod.getInstance());
}
//这句话确保,点击checkBox时,光标始终在最后,很有用呀
passwordEdit.setSelection(passwordEdit.getText().length());
}
});
这里关于EditText光标始终保持在最后,也是一种友好的用户体验哦。
- 验证码倒计时
这种获取验证码后倒计时的实现,一方面给用户一种良好的体验,同时也很大程度的避免了短信炸弹的问题
/**
* 验证码倒计时实现
*/
timer = new TimerCount(120, 1000, getCode);
getCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TextUtils.isEmpty(phoneNum.getText().toString())) {
T.showShort(mContext, "不能为空");
} else if (!ShoppingTools.isMobileNO(phoneNum.getText().toString())) {
T.showShort(mContext, "请输入正确的手机号");
} else {
timer.start();
}
}
});
这里首先判断了输入有效性,关于手机号有效性的判断在网络上有很多正则表达式实现,这里就不再赘述。
我们看一下TimerCount类
public class TimerCount extends CountDownTimer {
private Button bnt;
public TimerCount(long millisInFuture, long countDownInterval, Button bnt) {
super(millisInFuture*1000, countDownInterval);
this.bnt = bnt;
}
@Override
public void onFinish() {
// TODO Auto-generated method stub
bnt.setClickable(true);
bnt.setBackgroundResource(R.color.addtocar);
bnt.setText("获取短信校验码");
}
@Override
public void onTick(long arg0) {
// TODO Auto-generated method stub
bnt.setClickable(false);
bnt.setBackgroundResource(R.color.yahui);
bnt.setText("("+arg0 / 1000 + ")秒后重新获取");
}
}
这个类继承自CountDownTimer ,并在其OnTick方法和onFinish方法中,实现构造函数中所使用View内容的动态变化。这里以Button为例,当然用ImageView也是OK 的,根据实际情况做调整即可,主要思路是一样。
- 动态验证码实现
对于这个动态验证码,在12306购买过火车票的同学一定不陌生,从登录到购票,每一年为了回家而抢票的那几天,不知道输了多少次验证码。当然了,现在的验证码已不像图中这么简单,但在日常APP登录验证中用到的还是很多。
/**
* 图片验证码获取及验证
*/
codeImg.setImageBitmap(SecurityCode.getInstance().createBitmap(300, 100, 15, mContext));
/**
* 点击图片生成新的验证码
*/
codeImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
codeImg.setImageBitmap(SecurityCode.getInstance().createBitmap(300, 100, 15, mContext));
}
});
verifyCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (SecurityCode.getInstance().Verification(inputCode.getText().toString().trim())) {
T.showShort(mContext, "OK");
} else {
T.showShort(mContext, "WRONG");
}
}
});
这里看一下SecurityCode这个类。
public class SecurityCode {
private static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
private static SecurityCode bmpCode;
public static SecurityCode getInstance() {
if (bmpCode == null)
bmpCode = new SecurityCode();
return bmpCode;
}
private static final int DEFAULT_CODE_LENGTH = 4;// 随机字符的个数
private String code;
private Random random = new Random();
/**
* 生成验证码图片
*
* @param width 宽度
* @param height 高度
* @param size 字体大小(以sp为单位计算)
* @param context
* @return
*/
public Bitmap createBitmap(int width, int height, int size, Context context) {
int textSize = DensityUtils.sp2px(context, size);
Bitmap codeBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(codeBitmap);
TextPaint textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(textSize);
textPaint.setStrokeWidth(3);
textPaint.setStyle(Paint.Style.STROKE);
textPaint.setTextAlign(Paint.Align.CENTER);
code = createCode();
int x = (width - textSize * 3) / 2;
int y = (height + textSize) / 2;
for (int index = 0; index < code.length(); index++) {
textPaint.setColor(randomColor(1));
canvas.drawText(code.charAt(index) + "", (x + textSize * index), y, textPaint);
}
Random random = new Random();
for (int i = 0; i < 5; i++) {
textPaint.setStrokeWidth(2);
textPaint.setColor(randomColor(1));
canvas.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width),
random.nextInt(height), textPaint);
}
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
return codeBitmap;
}
public String getCode() {
return code;
}
public boolean Verification(String input){
if (TextUtils.isEmpty(code))
return false;
if (TextUtils.isEmpty(input))
return false;
return code.equalsIgnoreCase(input);
}
// 验证码
private String createCode() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < DEFAULT_CODE_LENGTH; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
// 随机颜色
private int randomColor(int rate) {
int red = random.nextInt(256) / rate;
int green = random.nextInt(256) / rate;
int blue = random.nextInt(256) / rate;
return Color.rgb(red, green, blue);
}
}
对于这个实现的整体思路很简单,就是从定义好的数组中随机获取4个 (这里的默认值,当然也可以设定)字符,分别设置随机的4个颜色,使用Canvas绘制出一副图片。
当然了,在实际开发中,在本地动态的生成验证码并完成校验,完全就是此地无银三百两的一种做法。更好的方式是,从服务器获取图片,并且由服务器完成用户输入校验。这里只是去了解了一下这种图片验证码实现方式,以备不时之需。
- BadgeView
这个BadgeView 也是很常见,每天打开手机,桌面上各种未读消息都会以各种小红圈加数字的方式提醒我们,赶紧去打开APP(尤其是对于某些强迫症患者)
/**
* 角标更新
*/
BadgeView numView = new BadgeView(mContext);
numView.setBackground(9, getResources().getColor(R.color.enablebtn));
numView.setTargetView(shopCarTab);
numView.setHideOnNull(false);
numView.setBadgeCount(0);
plusImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int value = Integer.valueOf(numTv.getText().toString());
value++;
numTv.setText(String.valueOf(value));
numView.setBadgeCount(value);
}
});
subImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int value = Integer.valueOf(numTv.getText().toString());
if (value > 1) {
value--;
}
numTv.setText(String.valueOf(value));
numView.setBadgeCount(value);
}
});
这里简单模拟下购物车添加商品时,车内商品数量的变化。BadgeView作为Github上有名的开源项目,代码就不再这里贴出。
好了,widget的第一次总结就先到这里。