咱們都知道,購物車是作商城項目必不可少的一個環節,購物車中的加減控件就是商城中的重中之重,最近項目中也用到了加減控件,可是使用起來樣式不能隨便更改,決定簡單封裝一下,之後用到的時候就不那麼麻煩了,幾行代碼就搞定。本文主要是對封裝的過程進行一下整理。android
Github地址:AddSubUtilsgit
同步csdn和簡書:
csdn地址:商城購物車加減控件的簡單封裝
簡書地址:商城購物車加減控件的簡單封裝github
這裏涵蓋了大部分的加減控件的需求,對於咱們來講,咱們只須要簡單的調用就ok了,因此接下來會把邏輯處理部分封裝在一個類中,而且自定義屬性,可讓咱們隨時更改樣式。bash
簡單理一下思路,第一點若是支持手動輸入,TextView是知足不了需求的,這裏使用EditText,第二點,我們把關於樣式的放在自定義屬性中,在xml代碼中去控制,至於最大值、庫存、步長、最小值等放在代碼中調用的時候賦值,默認最大值和庫存都爲int的最大值,即Integer.MAX_VALUE,步長、當前值和最小值爲1。微信
佈局:add_sub_layout.xmlapp
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="@drawable/divider_horizontal"
android:background="@drawable/addsubutils_add_sub_bg"
android:orientation="horizontal">
<ImageView
android:id="@+id/ic_minus"
android:layout_width="@dimen/addsubutils_btn_width"
android:layout_height="match_parent"
android:background="@drawable/addsubutils_left_selector"
android:clickable="true"
android:padding="@dimen/addsubutils_btn_padding"
android:scaleType="centerInside"
android:src="@drawable/addsubutils_ic_minus" />
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:cursorVisible="true"
android:digits="0123456789"
android:gravity="center"
android:singleLine="true"
android:inputType="number"
android:minWidth="@dimen/addsubutils_et_minwidth"
android:text="1"
android:textColor="@color/addsubutils_text"
android:textCursorDrawable="@null"
android:textSize="@dimen/addsubutils_textsize"/>
<ImageView
android:id="@+id/ic_plus"
android:layout_width="@dimen/addsubutils_btn_width"
android:layout_height="match_parent"
android:background="@drawable/addsubutils_right_selector"
android:clickable="true"
android:padding="@dimen/addsubutils_btn_padding"
android:scaleType="centerInside"
android:src="@drawable/addsubutils_ic_plus" />
</LinearLayout>複製代碼
這裏很是簡單,就是一個水平的Linear包裹了兩個ImageView和一個EditText,這裏用到幾種的樣式ide
總體背景樣式:addsubutils_add_sub_bg.xml佈局
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="1dp"
android:color="@color/divider"/>
<corners android:radius="3dp"/>
</shape>複製代碼
左邊按鈕默認背景樣式:addsubutils_left_selector.xml字體
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="200" android:exitFadeDuration="200">
<item android:state_pressed="true" >
<shape>
<stroke android:color="@color/divider"
android:width="1dp"/>
<solid android:color="@color/divider"/>
<corners android:topLeftRadius="3dp"
android:bottomLeftRadius="3dp"/>
</shape>
</item>
<item android:state_pressed="false" >
<shape>
<stroke android:color="@color/divider"
android:width="1dp"/>
<corners android:topLeftRadius="3dp"
android:bottomLeftRadius="3dp"/>
</shape>
</item>
</selector>複製代碼
右邊按鈕默認背景樣式:addsubutils_right_selector.xmlgradle
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="200" android:exitFadeDuration="200">
<item android:state_pressed="true" >
<shape>
<stroke android:color="@color/divider"
android:width="1dp"/>
<solid android:color="@color/divider"/>
<corners android:topRightRadius="3dp"
android:bottomRightRadius="3dp"/>
</shape>
</item>
<item android:state_pressed="false" >
<shape>
<stroke android:color="@color/divider"
android:width="1dp"/>
<corners android:topRightRadius="3dp"
android:bottomRightRadius="3dp"/>
</shape>
</item>
</selector>複製代碼
dimens中字體大小和邊距
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="addsubutils_btn_width" >30dp</dimen>
<dimen name="addsubutils_btn_padding">10dp</dimen>
<dimen name="addsubutils_textsize" >15sp</dimen>
<dimen name="addsubutils_et_minwidth" >65dp</dimen>
</resources>複製代碼
分割線divider_horizontal的樣式
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1dp"/>
<solid android:color="@color/divider"/>
</shape>複製代碼
用到的圖片:
/**
* Created by 賈夢飛 on 2017/8/10 10:55.
* QQ:821176301
* 微信:j821176301
* desc:購物車功能的增長和加減
*/
public class AddSubUtils extends LinearLayout {
private EditText etInput;
private ImageView icPlus;
private ImageView icMinus;
public AddSubUtils(Context context) {
this(context, null);
}
public AddSubUtils(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AddSubUtils(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
// 把佈局和當前類造成總體
LayoutInflater.from(context).inflate(R.layout.add_sub_layout, this);
icPlus = (ImageView) findViewById(R.id.ic_plus);
icMinus = (ImageView) findViewById(R.id.ic_minus);
etInput = (EditText) findViewById(R.id.et_input);
}
}複製代碼
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
//獲得屬性
if (attrs != null) {
TypedArray typeArray = getContext().obtainStyledAttributes(attrs, R.styleable.AddSubUtils);
boolean editable = typeArray.getBoolean(R.styleable.AddSubUtils_editable, true);
String location = typeArray.getString(R.styleable.AddSubUtils_location);
// 左右兩面的寬度
int ImageWidth = typeArray.getDimensionPixelSize(R.styleable.AddSubUtils_ImageWidth, -1);
// 中間內容框的寬度
int contentWidth = typeArray.getDimensionPixelSize(R.styleable.AddSubUtils_contentWidth, -1);
// 中間字體的大小
int contentTextSize = typeArray.getDimensionPixelSize(R.styleable.AddSubUtils_contentTextSize, -1);
// 中間字體的顏色
int contentTextColor = typeArray.getColor(R.styleable.AddSubUtils_contentTextColor, 0xff000000);
// 整個控件的background
Drawable background = typeArray.getDrawable(R.styleable.AddSubUtils_all_background);
// 左面控件的背景
Drawable leftBackground = typeArray.getDrawable(R.styleable.AddSubUtils_leftBackground);
// 右面控件的背景
Drawable rightBackground = typeArray.getDrawable(R.styleable.AddSubUtils_rightBackground);
// 中間控件的背景
Drawable contentBackground = typeArray.getDrawable(R.styleable.AddSubUtils_contentBackground);
// 左面控件的資源
Drawable leftResources = typeArray.getDrawable(R.styleable.AddSubUtils_leftResources);
// 右面控件的資源
Drawable rightResources = typeArray.getDrawable(R.styleable.AddSubUtils_rightResources);
// 資源回收
typeArray.recycle();
// 若是是start就說明輸入框在左邊,若是是end說明輸入框在右面,不然默認是在中間
if("start".equals(location)) {
//把佈局和當前類造成總體
LayoutInflater.from(context).inflate(R.layout.add_sub_start_layout, this);
}else if("end".equals(location)) {
//把佈局和當前類造成總體
LayoutInflater.from(context).inflate(R.layout.add_sub_end_layout, this);
}else {
//把佈局和當前類造成總體
LayoutInflater.from(context).inflate(R.layout.add_sub_layout, this);
}
icPlus = (ImageView) findViewById(R.id.ic_plus);
icMinus = (ImageView) findViewById(R.id.ic_minus);
etInput = (EditText) findViewById(R.id.et_input);
// 設置EditText是否可點擊
setEditable(editable);
etInput.setTextColor(contentTextColor);
// 設置兩邊按鈕的寬度
if (ImageWidth > 0) {
LayoutParams textParams = new LayoutParams(ImageWidth, LayoutParams.MATCH_PARENT);
icPlus.setLayoutParams(textParams);
icMinus.setLayoutParams(textParams);
}
// 設置中間輸入框的寬度
if (contentWidth > 0) {
LayoutParams textParams = new LayoutParams(contentWidth, LayoutParams.MATCH_PARENT);
etInput.setLayoutParams(textParams);
}
if (contentTextColor > 0) {
etInput.setTextSize(contentTextColor);
}
if(contentTextSize > 0) {
etInput.setTextSize(contentTextSize);
}
if (background != null) {
setBackgroundDrawable(background);
} else {
setBackgroundResource(R.drawable.addsubutils_add_sub_bg);
}
if (contentBackground != null) {
etInput.setBackground(contentBackground);
}
if(leftBackground != null) {
icMinus.setBackground(leftBackground);
}
if (rightBackground != null){
icPlus.setBackground(rightBackground);
}
if (leftResources != null){
icMinus.setImageDrawable(leftResources);
}
if(rightResources != null) {
icPlus.setImageDrawable(rightResources);
}
}
}
private void setEditable(boolean editable) {
if (editable) {
etInput.setFocusable(true);
etInput.setKeyListener(new DigitsKeyListener());
} else {
etInput.setFocusable(false);
etInput.setKeyListener(null);
}
}複製代碼
首先使用TypedArray獲得自定義屬性值,而後傳給對應的控件,這裏註釋寫的很詳細。
在init()方法中:
icPlus.setOnClickListener(this);
icMinus.setOnClickListener(this);
etInput.addTextChangedListener(this);複製代碼
AddSubUtils類實現View.OnClickListener, TextWatcher這兩個接口,並重寫onClick()和其餘的方法
public class AddSubUtils extends LinearLayout implements View.OnClickListener, TextWatcher {
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.ic_plus) {
// 加
if (inputValue < Math.min(mBuyMax, inventory)) {
inputValue += mStep;
//正常添加
etInput.setText("" + inputValue);
} else if (inventory < mBuyMax) {
//庫存不足
warningForInventory();
} else {
//超過最大購買數
warningForBuyMax();
}
} else if (id == R.id.ic_minus) {
// 減
if (inputValue > mBuyMin) {
inputValue -= mStep;
etInput.setText(inputValue + "");
} else {
// 低於最小購買數
warningForBuyMin();
}
} else if (id == R.id.et_input) {
// 輸入框
etInput.setSelection(etInput.getText().toString().length());
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
onNumberInput();
}
/**
* 監聽輸入的數據變化
*/
private void onNumberInput() {
//當前數量
int count = getNumber();
if (count < mBuyMin) {
//手動輸入
etInput.setText(mBuyMin + "");
return;
}
int limit = Math.min(mBuyMax, inventory);
if (count > limit) {
if (inventory < mBuyMax) {
//庫存不足
warningForInventory();
} else {
//超過最大購買數
warningForBuyMax();
}
}else{
inputValue = count;
}
}
}複製代碼
這裏具體邏輯你們一看就明白,我就再也不重複了
public interface OnWarnListener {
// 不能超過庫存
void onWarningForInventory(int inventory);
// 不能超過購買最大數
void onWarningForBuyMax(int max);
// 不能低於最小購買數
void onWarningForBuyMin(int min);
}複製代碼
public AddSubUtils setCurrentNumber(int currentNumber) {
if (currentNumber < mBuyMin){
inputValue = mBuyMin;
} else {
inputValue = Math.min(Math.min(mBuyMax, inventory), currentNumber);
}
etInput.setText(inputValue + "");
return this;
}
public int getInventory() {
return inventory;
}
public AddSubUtils setInventory(int inventory) {
this.inventory = inventory;
return this;
}
public int getBuyMax() {
return mBuyMax;
}
public AddSubUtils setBuyMax(int buyMax) {
mBuyMax = buyMax;
return this;
}
public AddSubUtils setBuyMin(int buyMin) {
mBuyMin = buyMin;
return this;
}
public AddSubUtils setOnWarnListener(OnWarnListener onWarnListener) {
mOnWarnListener = onWarnListener;
return this;
}
public int getStep() {
return mStep;
}
public AddSubUtils setStep(int step) {
mStep = step;
return this;
}複製代碼
到這裏你已經封裝完成了,具體demo能夠去Github下載
dependencies {
compile 'com.mengfei:AddSubUtils:1.0.0'
}複製代碼
或者下載源碼包,連接:github.com/Jmengfei/Ad… ,而且在build.gradle中添加:
dependencies {
compile project(':addsubutils')
}複製代碼
<com.mengfei.AddSubUtils
android:id="@+id/add_sub"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />複製代碼
你也能夠自定義樣式:
<com.mengfei.AddSubUtils
android:id="@+id/add_sub_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
jmf:editable="true"
jmf:ImageWidth="60dp"
jmf:contentTextColor="@color/colorText"
jmf:contentWidth="120dp"
jmf:contentTextSize="16sp"
jmf:contentBackground="@color/material_teal_200"
jmf:leftBackground="@drawable/left_selector"
jmf:rightBackground="@drawable/right_selector"
jmf:leftResources="@drawable/minus"
jmf:rightResources="@drawable/plus"/>複製代碼
AddSubUtils addSubUtils = (AddSubUtils) findViewById(R.id.add_sub);
addSubUtils.setBuyMax(30) // 最大購買數,默認爲int的最大值
.setInventory(50) // 庫存,默認爲int的最大值
.setCurrentNumber(5) // 設置當前數,默認爲1
.setStep(5) // 步長,默認爲1
.setBuyMin(2) // 購買的最小值,默認爲1
.setOnWarnListener(new AddSubUtils.OnWarnListener() {
@Override
public void onWarningForInventory(int inventory) {
Toast.makeText(MainActivity.this, "當前庫存:" + inventory, Toast.LENGTH_SHORT).show();
}
@Override
public void onWarningForBuyMax(int max) {
Toast.makeText(MainActivity.this, "超過最大購買數:" + max, Toast.LENGTH_SHORT).show();
}
@Override
public void onWarningForBuyMin(int min) {
Toast.makeText(MainActivity.this, "低於最小購買數:" + min, Toast.LENGTH_SHORT).show();
}
});複製代碼
這裏你只須要傳入你關心的值便可。
Attributes | forma | describe |
---|---|---|
editable | boolean | 是否能夠手動輸入 |
location | string | 輸入框的位置(在左邊仍是右邊),默認中間 |
ImageWidth | dimension | 左右2邊+-按鈕的寬度 |
contentWidth | dimension | 中間EditText的寬度 |
contentTextSize | dimension | 中間EditText的字體大小 |
contentTextColor | color | 中間字體的顏色 |
all_background | color/reference | 整個控件的background |
leftBackground | color/reference | 左面控件的背景 |
rightBackground | color/reference | 右面控件的背景 |
contentBackground | color/reference | 中間控件的背景 |
leftResources | color/reference | 左面控件的資源 |
rightResources | color/reference | 右面控件的資源 |
以上就是對商城購物車加減控件的一些介紹和一個簡單的封裝。須要源碼的朋友,請看 Github地址:AddSubUtils,若是以爲對你有用的話,歡迎star。
客官別走
在v1.5.0版本中解決了在ListView中因爲item的複用致使數據錯亂的問題:
地址: 商城購物車加減控件的簡單封裝(續),解決ListView中數據錯亂的問題 若是你以爲對你有用的話,不妨留下你的足跡。