將「減」按鈕、「加」按鈕及中間的數值,做成一個Component
這樣的好處是你的Activity會比較乾淨,加減Button的Click事件及邏輯在component處理,而不在Activity。
在做單元測試時,也會較方便,單獨針對這個Component測試就好。
新增一個 NumberSelect Layout
這個Layout裡有一個「-」Button、「+」Button、TextView數字
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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="wrap_content" | |
android:background="@drawable/number_select_background"> | |
<Button | |
android:id="@+id/minusButton" | |
android:layout_width="50dp" | |
android:layout_height="wrap_content" | |
android:padding="0dp" | |
android:text="-" | |
android:textSize="32sp" /> | |
<TextView | |
android:id="@+id/valueTextView" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:width="30dp" | |
android:gravity="center" | |
android:layout_gravity="center_horizontal|center_vertical" | |
android:textColor="@color/colorPrimary" /> | |
<Button | |
android:id="@+id/addButton" | |
android:layout_width="50dp" | |
android:layout_height="wrap_content" | |
android:padding="0dp" | |
android:text="+" | |
android:textSize="32sp" /> | |
</LinearLayout> |
設定custom attributes
在 values 裡新增 attrs.xml ,分別是min_value最小值、max_value最大值、default_value預設值。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="NumberSelect"> | |
<attr name="default_value" format="integer" /> | |
<attr name="min_value" format="integer" /> | |
<attr name="max_value" format="integer" /> | |
</declare-styleable> | |
</resources> |
在Layout 設定屬性
attrs.xml 這裡設定好了之後,就可直接在layout上設定defaultValue、minValue、maxValue屬性。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<android.support.constraint.ConstraintLayout | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:padding="10dp" | |
tools:context="evan.chen.app.componentsample.MainActivity"> | |
<evan.chen.app.componentsample.NumberSelect | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:id="@+id/number_select" | |
app:default_value="3" | |
app:min_value="0" | |
app:max_value="20" | |
/> | |
</android.support.constraint.ConstraintLayout> |
建立NumberSelect.java
這段程式有點長,見下方的說明。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class NumberSelect extends LinearLayout { | |
Button addButton; | |
Button minusButton; | |
TextView valueTextView; | |
private int minValue; | |
private int maxValue; | |
private int defaultValue; | |
private int textValue; | |
public interface NumberSelectListener { | |
public void onValueChange(int value); | |
} | |
private NumberSelectListener listener; | |
public NumberSelect(Context context) { | |
super(context); | |
init(context, null); | |
} | |
public NumberSelect(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(context, attrs); | |
} | |
public NumberSelect(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(context, attrs); | |
} | |
private void init(Context context, AttributeSet attrs) { | |
View.inflate(context, R.layout.number_select, this); | |
setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS); | |
this.addButton = (Button) findViewById(R.id.addButton); | |
this.minusButton = (Button) findViewById(R.id.minusButton); | |
this.valueTextView = (TextView) findViewById(R.id.valueTextView); | |
this.textValue = 0; | |
this.maxValue = Integer.MAX_VALUE; | |
this.minValue = 0; | |
if (attrs != null) { | |
TypedArray attributes = context.getTheme().obtainStyledAttributes( | |
attrs, | |
R.styleable.NumberSelect, | |
0, 0); | |
this.maxValue = attributes.getInt(R.styleable.NumberSelect_max_value, this.maxValue); | |
this.minValue = attributes.getInt(R.styleable.NumberSelect_min_value, this.minValue); | |
this.defaultValue = attributes.getInt(R.styleable.NumberSelect_default_value, 0); | |
this.valueTextView.setText(String.valueOf(defaultValue)); | |
} | |
this.addButton.setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
addTextValue(); | |
if ( listener != null) { | |
listener.onValueChange(textValue); | |
} | |
} | |
}); | |
this.minusButton.setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
minusTextValue(); | |
if ( listener != null) { | |
listener.onValueChange(textValue); | |
} | |
} | |
}); | |
} | |
public void setMaxValue(int value) { | |
this.maxValue = value; | |
} | |
public void setMinValue(int value) { | |
this.minValue = value; | |
} | |
public void setDefaultValue(int value) { | |
this.defaultValue = value; | |
} | |
private void addTextValue(){ | |
if ( this.textValue < this.maxValue) { | |
this.textValue++; | |
this.valueTextView.setText(String.valueOf(this.textValue)); | |
} | |
} | |
private void minusTextValue(){ | |
if ( this.textValue > this.minValue) { | |
this.textValue--; | |
this.valueTextView.setText(String.valueOf(this.textValue)); | |
} | |
} | |
public void setListener(NumberSelectListener listener) { | |
this.listener = listener; | |
} | |
} |
在init 裡,取得在layout的min_value、max_value、default_value屬性。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void init(Context context, AttributeSet attrs) { | |
View.inflate(context, R.layout.number_select, this); | |
setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS); | |
this.addButton = (Button) findViewById(R.id.addButton); | |
this.minusButton = (Button) findViewById(R.id.minusButton); | |
this.valueTextView = (TextView) findViewById(R.id.valueTextView); | |
this.textValue = 0; | |
this.maxValue = Integer.MAX_VALUE; | |
this.minValue = 0; | |
//get Attributes from component layout | |
if (attrs != null) { | |
TypedArray attributes = context.getTheme().obtainStyledAttributes( | |
attrs, | |
R.styleable.NumberSelect, | |
0, 0); | |
this.maxValue = attributes.getInt(R.styleable.NumberSelect_max_value, this.maxValue); | |
this.minValue = attributes.getInt(R.styleable.NumberSelect_min_value, this.minValue); | |
this.defaultValue = attributes.getInt(R.styleable.NumberSelect_default_value, 0); | |
this.valueTextView.setText(String.valueOf(defaultValue)); | |
} | |
} |
設定addButton、minusButton,加減份數時,異動中間的數值及設定callback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
this.addButton.setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
addTextValue(); | |
if ( listener != null) { | |
listener.onValueChange(textValue); | |
} | |
} | |
}); | |
this.minusButton.setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
minusTextValue(); | |
if ( listener != null) { | |
listener.onValueChange(textValue); | |
} | |
} | |
}); |
使用custom component
在 activity_main.xml 加入NumberSelect Custom Component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<android.support.constraint.ConstraintLayout | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:padding="10dp" | |
tools:context="evan.chen.app.componentsample.MainActivity"> | |
<evan.chen.app.componentsample.NumberSelect | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:id="@+id/number_select" | |
app:default_value="3" | |
app:min_value="0" | |
app:max_value="20" | |
/> | |
</android.support.constraint.ConstraintLayout> |
完整程式
https://github.com/evanchen76/ComponentSample
參考
Custom Components
天呀,你真的是我的救星
回覆刪除卡了兩天怎麼都找不到的解決方案
終於在此找到,太感謝你了!
謝謝,也歡迎到我的新網誌有更多文章喔。
刪除https://medium.com/@evanchen76
這幾天在研究ViewGroup, 這篇真是淺顯易懂!
回覆刪除謝謝,也歡迎到我的新網誌有更多文章喔。
刪除https://medium.com/@evanchen76