本文将介绍如何使用自定义控件实现计数器,效果如下所示:
主要功能:
1、实现计数功能
2、到达数值上限/下限无法点击
3、自定义控件暴露方法供外部使用
实现思路:
1、创建一个自定义控件的布局
2、写一个自定义组合控件的类,继承自LinearLayout/RelativLayout,实现前三个方法,统一构造函数的入口
3、使用时候将该类名copy references然后在布局中使用即可
4、利用自定义属性设置max,min,step
部分代码:
InputNumberView.class
/**
* description 自定义组合控件
* 使用步骤:
* 1、继承自LinearLayout/RelativeLayout,实现前3个构造方法,确保统一入口
* 2、把其他的子view加载进来
* 3、使用时候将该类名copy references然后在布局中使用即可
* 4、处理数据,处理事件
* 5、暴露接口
* create by xiaocai on 2020/6/21
*/
public class InputNumberView extends RelativeLayout {
private static final String TAG = "InputNumberView";
//当前的数值为0
private int mCurrentNumber = 0;
private View mMinusBtn;
private View mPlusBtn;
private EditText mNumberEt;
private OnNumberNumberChangeListener mOnNumberNumberChangeListener = null;
private int mMax;
private int mMin;
private int mStep;
private boolean mDisable;
private int mResourceId;
public InputNumberView(Context context) {
this(context, null);
}
public InputNumberView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public InputNumberView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
//获取相关属性
initAttrs(context, attrs);
//设置事件
sertUpEvent();
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.InputNumberView);
mMax = typedArray.getInt(R.styleable.InputNumberView_max, 0);
mMin = typedArray.getInt(R.styleable.InputNumberView_min, 0);
mStep = typedArray.getInt(R.styleable.InputNumberView_step, 1);
mDisable = typedArray.getBoolean(R.styleable.InputNumberView_disable, false);
mResourceId = typedArray.getResourceId(R.styleable.InputNumberView_btnBackground, -1);
Log.d(TAG, "mMax----->" + mMax);
Log.d(TAG, "mMin----->" + mMin);
Log.d(TAG, "mStep----->" + mStep);
Log.d(TAG, "mDisable----->" + mDisable);
Log.d(TAG, "mResourceId----->" + mResourceId);
}
public int getMax() {
return mMax;
}
public void setMax(int max) {
mMax = max;
}
public int getMin() {
return mMin;
}
public void setMin(int min) {
mMin = min;
}
public int getStep() {
return mStep;
}
public void setStep(int step) {
mStep = step;
}
public boolean isDisable() {
return mDisable;
}
public void setDisable(boolean disable) {
mDisable = disable;
}
public int getResourceId() {
return mResourceId;
}
public void setResourceId(int resourceId) {
mResourceId = resourceId;
}
private void sertUpEvent() {
//-
mMinusBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//在-到上限的时候设置可以+
mPlusBtn.setEnabled(true);
mCurrentNumber -= mStep;
if (mCurrentNumber <= mMin) {
mCurrentNumber = mMin;
Log.d(TAG, "超出下限");
//设置button为不可点击
mMinusBtn.setEnabled(!mDisable);
}
updateText();
}
});
//+
mPlusBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCurrentNumber += mStep;
//在+到上限的时候设置可以-
mMinusBtn.setEnabled(true);
if (mCurrentNumber >= mMax) {
mCurrentNumber = mMax;
Log.d(TAG, "超出上限");
//设置button为不可点击
mPlusBtn.setEnabled(!mDisable);
}
updateText();
}
});
}
/**
* 更新数字
*/
private void updateText() {
mNumberEt.setText(mCurrentNumber + "");
//更新数据,让listen监听数据变化
if (mOnNumberNumberChangeListener != null) {
mOnNumberNumberChangeListener.onNumberChange(mCurrentNumber);
}
}
private void initView(Context context) {
//将子view加载进来
//inflate中的参数:布局文件,根布局(此处的根布局就是当前这个布局即this),attach(true:把从布局中加载的view绑定到当前布局中去;false:需要自己手动添加一下)
//attach:true的情况(默认为true,可以不填内容)
LayoutInflater.from(context).inflate(R.layout.input_number_view, this, true);
//attach:false
// View view = LayoutInflater.from(context).inflate(R.layout.input_number_view, this, false);
// this.addView(view);
//找到控件
mMinusBtn = findViewById(R.id.minus_btn);
mPlusBtn = findViewById(R.id.plus_btn);
mNumberEt = findViewById(R.id.number);
//初始化控件值
updateText();
}
/**
* 暴露方法让外部去设置数值
*
* @return
*/
public int getNumber() {
return mCurrentNumber;
}
public void setNumver(int number) {
mCurrentNumber = number;
updateText();
}
public void setOnNumberNumberChangeListener(OnNumberNumberChangeListener listener) {
this.mOnNumberNumberChangeListener = listener;
}
public interface OnNumberNumberChangeListener {
void onNumberChange(int value);
}
}
MainActivity.class:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InputNumberView inputNumberView=findViewById(R.id.number_view);
inputNumberView.setOnNumberNumberChangeListener(new InputNumberView.OnNumberNumberChangeListener() {
@Override
public void onNumberChange(int value) {
Toast.makeText(MainActivity.this, "num is "+value, Toast.LENGTH_SHORT).show();
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:xiaocai="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:gravity="center"
tools:context=".MainActivity">
<com.example.customview.customView.InputNumberView
android:id="@+id/number_view"
android:layout_width="wrap_content"
xiaocai:max="10"
xiaocai:min="-10"
xiaocai:disable="true"
xiaocai:step="2"
xiaocai:btnBackground="@drawable/shape_num_btn_bg_right"
android:layout_height="wrap_content" />
</LinearLayout>
input_number_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/minus_btn"
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="@drawable/selector_num_btn_bg_left"
android:gravity="center"
android:text="-"
android:textSize="30sp" />
<EditText
android:id="@+id/number"
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="@drawable/shape_num_inp_bg"
android:focusable="false"
android:gravity="center"
android:text="0"
android:textSize="16sp" />
<TextView
android:id="@+id/plus_btn"
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="@drawable/selector_num_btn_bg_right"
android:gravity="center"
android:text="+"
android:textSize="18sp" />
</LinearLayout>