Android,自定義IP控件IPEditText,這段時間,在寫智能電表采集APP,在UI界面關於IP人性化輸入上花瞭點時間,采用自定義控件的形式去實現。網上也有關於用TextWatcher實現IP的自定義的案例,但是存在些不足(數值范圍、控件聯動),本文采用TextWatcher+InputFilter+監聽KEYCODE_DEL去實現。關鍵代碼實現如下:
1.IPEditText樣式:
2.IPEditText實現類:
public class IPEditText extends LinearLayout implements TextWatcher {
private static final String TAG = "IPEditText";
private int width;
private int height;
private Paint paint;
private static final int DEFAULT_TEXT_MAX_LENGTH = 3;
private static final int DEFAULT_TEXT_SIZE = 16;
private static final int DEFAULT_TEXT_COLOR = Color.BLACK;
private static final int DEFAULT_BORDER_COLOR = Color.argb(60,0,0,0);
private static final int DEFAULT_BORDER_WIDTH = 2;
private static final int DEFAULT_POINT_COLOR = Color.BLACK;
private static final int DEFAULT_POINT_WIDTH = 2;
private static final int DEFAULT_IP_EDITTEXT_LENGTH = 4;
private int textLength;
private int textSize;
private int textColor;
private int borderColor;
private int borderWidth;
private int pointColor;
private int pointWidth;
private int editNumber;
private int default_height = px2dp(20);
private int default_width = px2dp(60);
private List data = new ArrayList<>();
public IPEditText(Context context) {
this(context, null);
}
public IPEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IPEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IPEditText, defStyleAttr, 0);
textLength = ta.getInt(R.styleable.IPEditText_textLength, DEFAULT_TEXT_MAX_LENGTH);
textSize = (int) ta.getDimension(R.styleable.IPEditText_IPtextSize, DEFAULT_TEXT_SIZE);
textColor = ta.getColor(R.styleable.IPEditText_IPtextColor, DEFAULT_TEXT_COLOR);
borderColor = ta.getColor(R.styleable.IPEditText_borderColor, DEFAULT_BORDER_COLOR);
borderWidth = (int) ta.getDimension(R.styleable.IPEditText_borderWidth, DEFAULT_BORDER_WIDTH);
pointColor = ta.getColor(R.styleable.IPEditText_pointColor, DEFAULT_POINT_COLOR);
pointWidth = (int) ta.getDimension(R.styleable.IPEditText_pointWidth, DEFAULT_POINT_WIDTH);
editNumber = ta.getInt(R.styleable.IPEditText_editNumber, DEFAULT_IP_EDITTEXT_LENGTH);
init(context);
initPaint();
}
public float getTextSize() {
return data.get(0).getTextSize();
}
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
}
private void init(Context context) {
for (int i = 0; i < editNumber; i++) {
EditText edit = new EditText(context);
edit.setBackground(null);
edit.setFilters(new InputFilter[]{new InputFilterMinMax("0", "255", "3")});
edit.setTextSize(textSize);
edit.setTextColor(textColor);
edit.setGravity(Gravity.CENTER);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
edit.setMinHeight(default_height);
edit.setMinWidth(default_width);
edit.setTag(i);
edit.setMaxLines(1);
edit.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1));
edit.addTextChangedListener(this);
edit.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mEditText = (EditText) v;
return false;
}
});
edit.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_DEL&event.getAction()==KeyEvent.ACTION_DOWN) {
//doSomething();
int a = data.indexOf(mEditText);
if (a > 0 & mEditText.getSelectionStart() == 0) {
data.get(a – 1).requestFocus();
mEditText = data.get(a – 1);
mEditText.setSelection(mEditText.length());
}
}
return false;
}
});
addView(edit);
data.add(edit);
}
setDividerDrawable(getResources().getDrawable(android.R.drawable.pider_horizontal_textfield));
setOrientation(LinearLayout.HORIZONTAL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int l = data.get(0).getLeft();
int t = data.get(0).getTop() – getPaddingTop();
int r = width – getPaddingRight();
int b = height;
paint.setColor(borderColor);
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawLine(0,height-5,width,height-5,paint);
int y = height-height/5;
int x = width / editNumber;
paint.setStrokeWidth(pointWidth);
paint.setColor(pointColor);
for (int i = 1; i < data.size(); i++) {
canvas.drawPoint(x * i, y, paint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
public EditText mEditText;
@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) {
if (listener != null) {
listener.afterTextChanged(getSuperEditTextValue());
}
if (s.length() == 3) {
int a = data.indexOf(mEditText);
if ( a < 3) {
data.get(a + 1).requestFocus();
mEditText = data.get(a + 1);
}
} else if (s.length() == 2) {
int a = data.indexOf(mEditText);
if ( a < 3&(Integer.parseInt(s.toString())>25)) {
data.get(a + 1).requestFocus();
mEditText = data.get(a + 1);
}
}
}
public String[] getSuperEditTextValue() {
String[] val = new String[editNumber];
for (int i = 0; i < editNumber; i++) {
val[i] = data.get(i).getText().toString();
// KLog.d(data.get(i).getText().toString());
}
return val;
}
public void setSuperEdittextValue(String[] s) {
for (int i = 0; i < s.length; i++) {
data.get(i).setText(s[i]);
}
}
public boolean getSuperCompile() {
for (int i = 0; i < editNumber; i++) {
String str = data.get(i).getText().toString();
if (Integer.parseInt(str) <= 255) {
return true;
}
}
return false;
}
public int px2dp(int val) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, val, getResources().getDisplayMetrics());
}
public int px2sp(int val) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, val, getResources().getDisplayMetrics());
}
public interface SuperTextWatcher {
public void afterTextChanged(String[] s);
}
private SuperTextWatcher listener;
public void setSuperTextWatcher(SuperTextWatcher listener) {
this.listener = listener;
}
public class InputFilterMinMax implements InputFilter {
private Double min, max;
private int maxCount;
public InputFilterMinMax(Double min, Double max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max, String maxCount) {
this.min = Double.parseDouble(min);
this.max = Double.parseDouble(max);
this.maxCount = Integer.parseInt(maxCount);
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
if (source.equals("-") & dest.toString().equals("")) {
return "-";
} else if (!dest.toString().contains("-") & source.toString().equals("-")) {
String strInut = source.toString() + dest.toString();
if (strInut.replace(".", "").replace("-", "").length() <= maxCount) {
Double input = Double.parseDouble(strInut);
if (isInRange(min, max, input))
return null;
} else {
return "";
}
} else {
String strInut = dest.toString() + source.toString();
if (strInut.replace(".", "").replace("-", "").length() <= maxCount) {
Double input = Double.parseDouble(strInut);
if (isInRange(min, max, input))
return null;
} else {
return "";
}
}
} catch (NumberFormatException nfe) {
}
return "";
}
private boolean isInRange(Double a, Double b, Double c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
}