Android EditText与GridLayout实现表格效果,实现ExclExcle效果,统计手机价格总和的简单实现
demo下载地址:DouYinWu-master案例集合.zip
效果图:
1.主函数布局:
2.主函数代码:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import com.example.qd.douyinwu.R;
import com.example.qd.douyinwu.utils.EditTextUtils;
import com.example.qd.douyinwu.utils.ExtendedEditText;
/**
* 网格布局使用
* https://www.cnblogs.com/Chenshuai7/p/5321766.html 计算器的布局
*
*
* GridLayout 使用总结
* https://blog.csdn.net/weixin_39251617/article/details/79711668
*
*
* Android自定义控件仿黑客帝国数字雨
* https://github.com/skateboard1991/NumberRain
*/
public class GridLayoutActivity extends AppCompatActivity {
private EditText etMiPrice;
private EditText etHwPrice;
private EditText etTotalPrice;
private double dMiPrice;
private double dHwPrice;
private double mTotalPriceMax = 99.0;//总价格最大值
private double mPriceMax = 60.0;//单价最大值
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_numberrain);//Android自定义控件仿黑客帝国数字雨
setContentView(R.layout.activity_gv_layout);
initView();
initData();
// setSupportActionBar(toolbar);
ExtendedEditText mInputView = (ExtendedEditText) findViewById(R.id.input);
mInputView.setClearDrawable(getResources().getDrawable(R.drawable.ic_clear));
// FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
// fab.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// mInputView.setClearDrawable(getResources().getDrawable(R.drawable.ic_clear));
// }
// });
}
/**
* 逻辑处理
* 小米手机单价不得大于60.00元人民币
* 华为手机单价不得大于60.00元人民币
* 小米、华为手机的总价不得大于99.00元人民币
*/
private void initData() {
//
java.text.DecimalFormat df = new java.text.DecimalFormat("#.0");//保留一位小数
// df.format(20);
// etMiPrice.setText(df.format(20)+"");
// etHwPrice.setText(df.format(30)+"");
//小米价格监听
EditTextUtils.setMiTextWatcher(etMiPrice,etHwPrice,etTotalPrice,"");
// etMiPrice.addTextChangedListener(new TextWatcher() {
// @Override
// public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//
// }
//
// @Override
// public void onTextChanged(CharSequence s, int start, int before, int count) {
//
// }
//
// @Override
// public void afterTextChanged(Editable s) {
// String MiPrice = s.toString();
// //将输入数值转成Double类型,保留一位小数
// if(!TextUtils.isEmpty(MiPrice)){
// //判断是否含有点,有则截取,否则转行类型会报异常
// if(MiPrice.contains(".")){
// String result = MiPrice.substring(0, MiPrice.indexOf("."));
// if(!TextUtils.isEmpty(result)){
// dMiPrice = Double.parseDouble(result);
// }
// }else {
// dMiPrice = Double.parseDouble(MiPrice);
// }
// if(dMiPrice > mPriceMax){
// etMiPrice.setError("小米手机单价不得大于" + mPriceMax + "元");
// etMiPrice.setText(mPriceMax+"");
// etMiPrice.setSelection(MiPrice.length());
// Animation shake = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shake);
// etMiPrice.startAnimation(shake);
// }
//
// //计算手机总价
// //判断华为手机价格
// String hwPrice = etHwPrice.getText().toString();
// if(!TextUtils.isEmpty(hwPrice)){
// if(hwPrice.contains(".")){
// String result = hwPrice.substring(0, hwPrice.indexOf("."));
// dHwPrice = Double.parseDouble(result);
// }else {
// dHwPrice = Double.parseDouble(hwPrice);
// }
// if(dHwPrice + dMiPrice > mTotalPriceMax){
// etMiPrice.setError("小米、华为手机总价不得大于" + mTotalPriceMax + "元");
// etMiPrice.setText("");
//// etMiPrice.setSelection(MiPrice.length());
// }
// }
//
// if(!TextUtils.isEmpty(hwPrice)&&!TextUtils.isEmpty(MiPrice)){
// etTotalPrice.setText(dHwPrice+dMiPrice+"");
// }
// }
//
// }
// });
//华为价格监听
EditTextUtils.setHwTextWatcher(etHwPrice,etMiPrice,etTotalPrice,"");
// etHwPrice.addTextChangedListener(new TextWatcher() {
// @Override
// public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//
// }
//
// @Override
// public void onTextChanged(CharSequence s, int start, int before, int count) {
//
// }
//
// @Override
// public void afterTextChanged(Editable s) {
// String HwPrice = s.toString();
// //将输入数值转成Double类型,保留一位小数
// if(!TextUtils.isEmpty(HwPrice)){
// //判断是否含有点,有则截取,否则转行类型会报异常
// if(HwPrice.contains(".")){
// String result = HwPrice.substring(0, HwPrice.indexOf("."));
// dHwPrice = Double.parseDouble(result);
//
// }else {
// dHwPrice = Double.parseDouble(HwPrice);
// }
// if(dHwPrice > mPriceMax){
// etHwPrice.setError("华为手机单价不得大于" + mPriceMax + "元");
// etHwPrice.setText(mPriceMax+"");
//// etHwPrice.setSelection(HwPrice.length());
// }
// //计算手机总价
// //判断小米手机价格
// String miPrice = etMiPrice.getText().toString();
// if(!TextUtils.isEmpty(miPrice)){
// if(miPrice.contains(".")){
// String result = miPrice.substring(0, miPrice.indexOf("."));
// dMiPrice = Double.parseDouble(result);
// }else {
// dMiPrice = Double.parseDouble(miPrice);
// }
// if(dHwPrice + dMiPrice > mTotalPriceMax){
// etHwPrice.setError("小米、华为手机总价不得大于" + mTotalPriceMax + "元");
// etHwPrice.setText("");
//// etHwPrice.setSelection(HwPrice.length());
// }
// }
// String hwPrice = etHwPrice.getText().toString();
//
// if(!TextUtils.isEmpty(hwPrice)&&!TextUtils.isEmpty(miPrice)){
// etTotalPrice.setText(dHwPrice+dMiPrice+"");
// }
// }
//
// }
// });
}
/**
* 初始化控件
*/
private void initView() {
etMiPrice = findViewById(R.id.et_mi_price);//小米手机官方售价
etHwPrice = findViewById(R.id.et_hw_price);//华为手机官方售价
etTotalPrice = findViewById(R.id.et_total_price);//官方售价合计
}
}
3.EditText工具类:
package com.example.qd.douyinwu.utils;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import com.example.qd.douyinwu.R;
/**
* EditText监听工具类
*/
public class EditTextUtils {
private static double dHwPrice;
private static double dMiPrice;
private static double mPriceMax = 60.0;//单价最大值
private static double mTotalPriceMax = 99.0;//总价格最大值
/**
* 设置华为价格监听逻辑
* @param hwEditText
* @param miEditText
* @param totalEditText
* @param str
*/
public static void setHwTextWatcher(final EditText hwEditText,final EditText miEditText, final EditText totalEditText,String str){
//华为价格监听
hwEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String HwPrice = s.toString();
//将输入数值转成Double类型,保留一位小数
if(!TextUtils.isEmpty(HwPrice)){
//判断是否含有点,有则截取,否则转行类型会报异常
if(HwPrice.contains(".")){
String result = HwPrice.substring(0, HwPrice.indexOf("."));
dHwPrice = Double.parseDouble(result);
}else {
dHwPrice = Double.parseDouble(HwPrice);
}
if(dHwPrice > mPriceMax){
hwEditText.setError("华为手机单价不得大于" + mPriceMax + "元");
hwEditText.setText(mPriceMax+"");
// etHwPrice.setSelection(HwPrice.length());
}
//计算手机总价
//判断小米手机价格
String miPrice = miEditText.getText().toString();
if(!TextUtils.isEmpty(miPrice)){
if(miPrice.contains(".")){
String result = miPrice.substring(0, miPrice.indexOf("."));
dMiPrice = Double.parseDouble(result);
}else {
dMiPrice = Double.parseDouble(miPrice);
}
if(dHwPrice + dMiPrice > mTotalPriceMax){
hwEditText.setError("小米、华为手机总价不得大于" + mTotalPriceMax + "元");
hwEditText.setText("");
// etHwPrice.setSelection(HwPrice.length());
}
}
String hwPrice = hwEditText.getText().toString();
if(!TextUtils.isEmpty(hwPrice)&&!TextUtils.isEmpty(miPrice)){
totalEditText.setText(dHwPrice+dMiPrice+"");
}
}
}
});
}
public static void setMiTextWatcher(final EditText miEditText,final EditText hwEditText, final EditText totalEditText,String str){
//小米价格监听
miEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String MiPrice = s.toString();
//将输入数值转成Double类型,保留一位小数
if(!TextUtils.isEmpty(MiPrice)){
//判断是否含有点,有则截取,否则转行类型会报异常
if(MiPrice.contains(".")){
String result = MiPrice.substring(0, MiPrice.indexOf("."));
if(!TextUtils.isEmpty(result)){
dMiPrice = Double.parseDouble(result);
}
}else {
dMiPrice = Double.parseDouble(MiPrice);
}
if(dMiPrice > mPriceMax){
miEditText.setError("小米手机单价不得大于" + mPriceMax + "元");
miEditText.setText(mPriceMax+"");
// miEditText.setSelection(MiPrice.length());
// Animation shake = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shake);
// miEditText.startAnimation(shake);
}
//计算手机总价
//判断华为手机价格
String hwPrice = hwEditText.getText().toString();
if(!TextUtils.isEmpty(hwPrice)){
if(hwPrice.contains(".")){
String result = hwPrice.substring(0, hwPrice.indexOf("."));
dHwPrice = Double.parseDouble(result);
}else {
dHwPrice = Double.parseDouble(hwPrice);
}
if(dHwPrice + dMiPrice > mTotalPriceMax){
miEditText.setError("小米、华为手机总价不得大于" + mTotalPriceMax + "元");
miEditText.setText("");
// etMiPrice.setSelection(MiPrice.length());
}
}
if(!TextUtils.isEmpty(hwPrice)&&!TextUtils.isEmpty(MiPrice)){
totalEditText.setText(dHwPrice+dMiPrice+"");
}
}
}
});
}
}
4.带有删除功能的输入框:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
/**
* ExtendedEditText is an extended EditText.
* To allow users to clear all input text
* and view(or hide) password.
*
*
* XML attributes
*
* @see {@link R.styleable#ExtendedEditText ExtendedEditText Attributes},
*
* @attr ref R.styleable#ExtendedEditText_clearDrawable
* @attr ref R.styleable#ExtendedEditText_eyeDrawable
* @attr ref R.styleable#ExtendedEditText_eyeOffDrawable
* @attr ref R.styleable#ExtendedEditText_enableClear
* @attr ref R.styleable#ExtendedEditText_enableEye
* @attr ref R.styleable#ExtendedEditText_buttonMargin
* @attr ref R.styleable#ExtendedEditText_buttonAlwaysCenter
*/
public class ExtendedEditText extends EditText {
private static final String LOG_TAG = "ExtendedEditText";
private Drawable mClearDrawable;
private Drawable mEyeDrawable;
private Drawable mEyeOffDrawable;
/** Whether this view allows users to clear text. */
private boolean mEnableClear;
/** Whether this view allows users to view password. */
private boolean mEnableEye;
/** The right margin of clear(eye) button. */
private int mButtonMargin;
/** Whether the buttons are always in the center of the view */
private boolean mButtonAlwaysCenter;
/** The input type set by users */
private int mInputType;
private Rect mClearRect;
private Rect mDrawClearRect;
private Rect mEyeRect;
private Rect mDrawEyeRect;
/** The right padding set by users */
private int mOriginalPaddingRight;
/** Whether the password is visible */
private boolean mIsEyeOff = false;
public ExtendedEditText(Context context) {
this(context, null);
}
public ExtendedEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mInputType = getInputType();
/* Get right padding set by users */
mOriginalPaddingRight = getPaddingRight();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtendedEditText,
defStyleAttr, 0);
mClearDrawable = a.getDrawable(R.styleable.ExtendedEditText_clearDrawable);
if (mClearDrawable == null) {
mClearDrawable = context.getResources()
.getDrawable(R.drawable.default_extended_edit_text_clear_drawable);
}
mEyeDrawable = a.getDrawable(R.styleable.ExtendedEditText_eyeDrawable);
if (mEyeDrawable == null) {
mEyeDrawable = context.getResources()
.getDrawable(R.drawable.default_extended_edit_text_eye_drawable);
}
mEyeOffDrawable = a.getDrawable(R.styleable.ExtendedEditText_eyeOffDrawable);
if (mEyeOffDrawable == null) {
mEyeOffDrawable = context.getResources()
.getDrawable(R.drawable.default_extended_edit_text_eye_off_drawable);
}
mEnableClear = a.getBoolean(R.styleable.ExtendedEditText_enableClear, true);
mEnableEye = a.getBoolean(R.styleable.ExtendedEditText_enableEye, true);
enableEye(mEnableEye);
mButtonMargin = a.getDimensionPixelSize(R.styleable.ExtendedEditText_buttonMargin,
context.getResources().getDimensionPixelSize(
R.dimen.default_extended_edit_text_button_margin));
mButtonAlwaysCenter = a.getBoolean(R.styleable.ExtendedEditText_buttonAlwaysCenter, true);
a.recycle();
/* Set new padding with clear button and eye button */
setPadding(getPaddingLeft(), getPaddingTop(), mOriginalPaddingRight, getPaddingBottom());
mClearRect = new Rect();
mDrawClearRect = new Rect();
mEyeRect = new Rect();
mDrawEyeRect = new Rect();
}
public void setClearDrawable(Drawable drawable) {
mClearDrawable = drawable;
invalidate();
}
public void setEyeDrawable(Drawable drawable) {
mEyeDrawable = drawable;
invalidate();
}
public void setEyeOffDrawable(Drawable drawable) {
mEyeOffDrawable = drawable;
invalidate();
}
public void setButtonMargin(int margin) {
mButtonMargin = margin;
invalidate();
}
public void setButtonAlwaysCenter(boolean alwaysCenter) {
mButtonAlwaysCenter = alwaysCenter;
requestLayout();
}
public void enableClear(boolean enable) {
mEnableClear = enable;
invalidate();
}
public void enableEye(boolean enable) {
mEnableEye = enable && isPasswordInputType();
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int scrollX = getScrollX();
final int scrollY = getScrollY();
if (isClearEnable()) {
mDrawClearRect.set(
mClearRect.left + scrollX,
mClearRect.top+ scrollY,
mClearRect.right + scrollX,
mClearRect.bottom+ scrollY
);
mClearDrawable.setBounds(mDrawClearRect);
mClearDrawable.draw(canvas);
}
if (isEyeEnable()) {
mDrawEyeRect.set(
mEyeRect.left + scrollX,
mEyeRect.top+ scrollY,
mEyeRect.right + scrollX,
mEyeRect.bottom+ scrollY);
mEyeDrawable.setBounds(mDrawEyeRect);
if (mIsEyeOff && mEyeOffDrawable != null) {
mEyeOffDrawable.setBounds(mDrawEyeRect);
mEyeOffDrawable.draw(canvas);
} else if (!mIsEyeOff) {
mEyeDrawable.draw(canvas);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/*
* If users touch inside clear button and enable clear, clear text.
* Else if users touch inside eye button and enable view password,
* show the text if it's invisible, else, hide it.
*/
float x;
float y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
x = event.getX();
y = event.getY();
if ((isInsideClear(x, y) && isClearEnable())
|| (isInsideEye(x, y) && isEyeEnable())) {
return true;
}
break;
}
case MotionEvent.ACTION_UP: {
x = event.getX();
y = event.getY();
if (isInsideClear(x, y) && isClearEnable()) {
clear();
return false;
}
if (isEyeEnable() && isInsideEye(x, y)) {
if (mIsEyeOff) {
mIsEyeOff = false;
setInputType(mInputType);
setSelection(getText().length());
} else {
mIsEyeOff = true;
setInputType(InputType.TYPE_CLASS_TEXT);
setSelection(getText().length());
}
return false;
}
break;
}
}
return super.onTouchEvent(event);
}
private boolean isInsideClear(float x, float y) {
return mClearRect.contains((int) x, (int) y);
}
private boolean isInsideEye(float x, float y) {
return mEyeRect.contains((int) x, (int) y);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int width = getMeasuredWidth();
final int height = getMeasuredHeight();
final int gravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
int offset = 0;
int left;
int top;
/* Calculates the bounding rectangles of mEyeDrawable, mEyeOffDrawable,
* and mClearDrawable. The rectangle indicates the location of drawable
* int this view.
*/
if (mEnableEye && mEyeDrawable != null) {
offset += mButtonMargin + mEyeDrawable.getIntrinsicWidth();
left = width - offset;
if (mButtonAlwaysCenter) {
top = (height - mEyeDrawable.getIntrinsicHeight()) / 2;
} else {
if (gravity == Gravity.TOP) {
top = getPaddingTop();
} else if (gravity == Gravity.BOTTOM) {
top = height - getPaddingBottom() - mEyeDrawable.getIntrinsicHeight();
} else {
top = (height - mEyeDrawable.getIntrinsicHeight()) / 2;
}
}
mEyeRect.set(left, top, left + mEyeDrawable.getIntrinsicWidth(),
top + mEyeDrawable.getIntrinsicHeight());
mEyeDrawable.setBounds(mEyeRect);
if (mEyeOffDrawable != null) {
mEyeOffDrawable.setBounds(mEyeRect);
}
}
if (mEnableClear && mClearDrawable != null) {
offset += mButtonMargin + mClearDrawable.getIntrinsicWidth();
left = width - offset;
if (mButtonAlwaysCenter) {
top = (height - mClearDrawable.getIntrinsicHeight()) / 2;
} else {
if (gravity == Gravity.TOP) {
top = getPaddingTop();
} else if (gravity == Gravity.BOTTOM) {
top = height - getPaddingBottom() - mClearDrawable.getIntrinsicHeight();
} else {
top = (height - mClearDrawable.getIntrinsicHeight()) / 2;
}
}
// top = getPaddingTop() + (height - mClearDrawable.getIntrinsicHeight()) / 2;
mClearRect.set(left, top,
left + mClearDrawable.getIntrinsicWidth(),
top + mClearDrawable.getIntrinsicHeight());
mClearDrawable.setBounds(mClearRect);
}
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
mOriginalPaddingRight = right;
super.setPadding(left, top, getRealPaddingRight(right), bottom);
}
/**
* Returns new right padding. If it is enable to view password, plus
* the width of {@link #mEyeDrawable} and {@link #mButtonMargin}.
* If it is enable to clear text, plus the width of
* {@link #mClearDrawable} and {@link #mButtonMargin}.
*
* @param right The original right padding set by users
* @return The new right padding
*/
private int getRealPaddingRight(int right) {
if (mEnableEye && mEyeDrawable != null) {
right += mButtonMargin + mEyeDrawable.getIntrinsicWidth();
}
if (mEnableClear && mClearDrawable != null) {
right += mButtonMargin + mClearDrawable.getIntrinsicWidth();
}
return right;
}
/**
* Sets text null.
*/
private void clear() {
setText(null);
}
private boolean isEmpty() {
return TextUtils.isEmpty(getText().toString());
}
private boolean isClearEnable() {
return mEnableClear && !isEmpty() && mClearDrawable != null;
}
private boolean isEyeEnable() {
return mEnableEye && !isEmpty() && mEyeDrawable != null;
}
/**
* Returns whether the input type is password type.
*/
private boolean isPasswordInputType() {
final int variation =
mInputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
final boolean passwordInputType = variation
== (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
final boolean webPasswordInputType = variation
== (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD);
final boolean numberPasswordInputType = variation
== (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD);
return passwordInputType || webPasswordInputType || numberPasswordInputType;
}
}
attrs.xml:
config.xml:(图片请自己去找 https://www.iconfont.cn/)
@drawable/ic_clear_black_24dp
@drawable/ic_visibility_black_24dp
@drawable/ic_visibility_off_black_24dp
8dp
5. EditText文字输入飞入效果 https://blog.csdn.net/shenggaofei/article/details/52233128
参考:
https://github.com/vickykang/ExtendedEditText
https://github.com/HITGIF/TextFieldBoxes
https://github.com/HITGIF/TextFieldBoxes
https://www.jianshu.com/p/e4a6757c2bd0