Android實(shí)現(xiàn)淘寶選中商品尺寸的按鈕組實(shí)例
話不多說(shuō),先上個(gè)效果圖:

現(xiàn)在我們就來(lái)說(shuō)說(shuō)里面的一些原理把!
一、原理:
1.其實(shí)這里我們用到的是一個(gè)ViewGroup控件組,把這些按鈕加進(jìn)去就有這種效果了!不過(guò)這里要繼承ViewGroup(命名為:GoodsViewGroup)重寫(xiě)里面的一些方法。
2.主要的方法有:
GoodsViewGroup按鈕組的控件大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
里面的按鈕每個(gè)的位置坐標(biāo)
protected void onLayout(boolean changed, int l, int t, int r, int b)
這兩個(gè)方法的具體使用大家可以網(wǎng)上查閱資料,這里就不多說(shuō)了!
二、代碼:
/**
* Created by ShaoLin on 2016/8/22.
* 這里是類(lèi)似淘寶中商品尺寸按鈕組(這里做了支持button,textview)
*/
public class GoodsViewGroup<X extends TextView> extends ViewGroup {
public static final String BTN_MODE = "BTNMODE"; //按鈕模式
public static final String TEV_MODE = "TEVMODE"; //文本模式
private static final String TAG = "IViewGroup";
private final int HorInterval = 10; //水平間隔
private final int VerInterval = 10; //垂直間隔
private int viewWidth; //控件的寬度
private int viewHeight; //控件的高度
private ArrayList<String> mTexts = new ArrayList<>();
private Context mContext;
private int textModePadding = 15;
//正常樣式
private float itemTextSize = 18;
private int itemBGResNor = R.drawable.goods_item_btn_normal;
private int itemTextColorNor = Color.parseColor("#000000");
//選中的樣式
private int itemBGResPre = R.drawable.goods_item_btn_selected;
private int itemTextColorPre = Color.parseColor("#ffffff");
public GoodsViewGroup(Context context) {
this(context, null);
}
public GoodsViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
/**
* 計(jì)算控件的大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = measureWidth(widthMeasureSpec);
viewHeight = measureHeight(heightMeasureSpec);
Log.e(TAG, "onMeasure:" + viewWidth + ":" + viewHeight);
// 計(jì)算自定義的ViewGroup中所有子控件的大小
measureChildren(widthMeasureSpec, heightMeasureSpec);
// 設(shè)置自定義的控件MyViewGroup的大小
setMeasuredDimension(viewWidth, getViewHeight());
}
private int measureWidth(int pWidthMeasureSpec) {
int result = 0;
int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);
int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);
switch (widthMode) {
/**
* mode共有三種情況,取值分別為MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
* MeasureSpec.AT_MOST。
*
*
* MeasureSpec.EXACTLY是精確尺寸,
* 當(dāng)我們將控件的layout_width或layout_height指定為具體數(shù)值時(shí)如andorid
* :layout_width="50dip",或者為FILL_PARENT是,都是控件大小已經(jīng)確定的情況,都是精確尺寸。
*
*
* MeasureSpec.AT_MOST是最大尺寸,
* 當(dāng)控件的layout_width或layout_height指定為WRAP_CONTENT時(shí)
* ,控件大小一般隨著控件的子空間或內(nèi)容進(jìn)行變化,此時(shí)控件尺寸只要不超過(guò)父控件允許的最大尺寸即可
* 。因此,此時(shí)的mode是AT_MOST,size給出了父控件允許的最大尺寸。
*
*
* MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,
* 通過(guò)measure方法傳入的模式。
*/
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = widthSize;
break;
}
return result;
}
private int measureHeight(int pHeightMeasureSpec) {
int result = 0;
int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);
switch (heightMode) {
case MeasureSpec.UNSPECIFIED:
result = getSuggestedMinimumHeight();
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = heightSize;
break;
}
return result;
}
/**
* 覆寫(xiě)onLayout,其目的是為了指定視圖的顯示位置,方法執(zhí)行的前后順序是在onMeasure之后,因?yàn)橐晥D肯定是只有知道大小的情況下,
* 才能確定怎么擺放
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 遍歷所有子視圖
int posLeft = HorInterval;
int posTop = VerInterval;
int posRight;
int posBottom;
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
// 獲取在onMeasure中計(jì)算的視圖尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth();
if (posLeft + getNextHorLastPos(i) > viewWidth) {
posLeft = HorInterval;
posTop += (measureHeight + VerInterval);
}
posRight = posLeft + measuredWidth;
posBottom = posTop + measureHeight;
childView.layout(posLeft, posTop, posRight, posBottom);
posLeft += (measuredWidth + HorInterval);
}
}
//獲取控件的自適應(yīng)高度
private int getViewHeight() {
int viewwidth = HorInterval;
int viewheight = VerInterval;
if (getChildCount() > 0) {
viewheight = getChildAt(0).getMeasuredHeight() + VerInterval;
}
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
// 獲取在onMeasure中計(jì)算的視圖尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth();
if (viewwidth + getNextHorLastPos(i) > viewWidth) {
viewwidth = HorInterval;
viewheight += (measureHeight + VerInterval);
} else {
viewwidth += (measuredWidth + HorInterval);
}
}
return viewheight;
}
private int getNextHorLastPos(int i) {
return getChildAt(i).getMeasuredWidth() + HorInterval;
}
private OnGroupItemClickListener onGroupItemClickListener;
public void setGroupClickListener(OnGroupItemClickListener listener) {
onGroupItemClickListener = listener;
for (int i = 0; i < getChildCount(); i++) {
final X childView = (X) getChildAt(i);
final int itemPos = i;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
onGroupItemClickListener.onGroupItemClick(itemPos);
chooseItemStyle(itemPos);
}
});
}
}
//選中那個(gè)的樣式
public void chooseItemStyle(int pos) {
clearItemsStyle();
if (pos < getChildCount()) {
X childView = (X) getChildAt(pos);
childView.setBackgroundResource(itemBGResPre);
childView.setTextColor(itemTextColorPre);
setItemPadding(childView);
}
}
private void setItemPadding(X view) {
if (view instanceof Button) {
view.setPadding(textModePadding, 0, textModePadding, 0);
} else {
view.setPadding(textModePadding, textModePadding, textModePadding, textModePadding);
}
}
//清除Group所有的樣式
private void clearItemsStyle() {
for (int i = 0; i < getChildCount(); i++) {
X childView = (X) getChildAt(i);
childView.setBackgroundResource(itemBGResNor);
childView.setTextColor(itemTextColorNor);
setItemPadding(childView);
}
}
public void addItemViews(ArrayList<String> texts, String mode) {
mTexts = texts;
removeAllViews();
for (String text : texts) {
addItemView(text, mode);
}
}
private void addItemView(String text, String mode) {
X childView = null;
switch (mode) {
case BTN_MODE:
childView = (X) new Button(mContext);
break;
case TEV_MODE:
childView = (X) new TextView(mContext);
break;
}
childView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
childView.setTextSize(itemTextSize);
childView.setBackgroundResource(itemBGResNor);
setItemPadding(childView);
childView.setTextColor(itemTextColorNor);
childView.setText(text);
this.addView(childView);
}
public String getChooseText(int itemID) {
if (itemID >= 0) {
return mTexts.get(itemID);
}
return null;
}
public void setItemTextSize(float itemTextSize) {
this.itemTextSize = itemTextSize;
}
public void setItemBGResNor(int itemBGResNor) {
this.itemBGResNor = itemBGResNor;
}
public void setItemTextColorNor(int itemTextColorNor) {
this.itemTextColorNor = itemTextColorNor;
}
public void setItemBGResPre(int itemBGResPre) {
this.itemBGResPre = itemBGResPre;
}
public void setItemTextColorPre(int itemTextColorPre) {
this.itemTextColorPre = itemTextColorPre;
}
public interface OnGroupItemClickListener {
void onGroupItemClick(int item);
}
}
上面提供了可以設(shè)置按鈕組的item的一些樣式,還有這個(gè)GoodsViewGroup為什么要寫(xiě)成GoodsViewGroup<X extends TextView>這樣呢?其實(shí)這里我是想做一個(gè)泛型,可以使用與Button跟TextView,而這里的Button本生就是繼承TextView所以在代碼中還要進(jìn)行一個(gè)判斷,可以看上面方法setItemPadding(X view) 。那到了這里,有些好友可能就會(huì)問(wèn),為什么要搞兩個(gè)呢?
其實(shí)這里因?yàn)?code>TextView的不會(huì)自動(dòng)有設(shè)置padding的,而button是有自動(dòng)設(shè)置padding。這個(gè)時(shí)候你就要看看你是先要那種效果!不過(guò)通過(guò)我的代碼中如果是選擇TextView的話,這里也設(shè)置了一個(gè)padding給他,不然會(huì)很難看!
兩種模式的寫(xiě)法:
1.Button :
GoodsViewGroup<Button> mGroup; mGroup.addItemViews(viewtexts, GoodsViewGroup.BTN_MODE);
2.TextView
GoodsViewGroup<TextView> mGroup; mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);
三、Drawable文件:上面涉及到的按鈕選中與正常的兩個(gè)Drawable
1.goods_item_btn_normal.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solid android:color="#F5F5F5" /> <corners android:radius="15.0dip" /> </shape> </item> </layer-list>
2.goods_item_btn_selected.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solid android:color="#FE4F00" /> <corners android:radius="15.0dip" /> </shape> </item> </layer-list>
四、例子:
ButtonGroupActivity
/**
* Created by ShaoLin on 2016/8/22.
*/
public class ButtonGroupActivity extends Activity implements GoodsViewGroup.OnGroupItemClickListener, View.OnClickListener {
private GoodsViewGroup<TextView> mGroup;
private Button mSubmitBtn;
private ArrayList<String> viewtexts = new ArrayList<>();
private int chooseID = -1;
private String chooseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_buttongroup);
mGroup = (GoodsViewGroup) findViewById(R.id.viewGroup);
mSubmitBtn = (Button) findViewById(R.id.submitBtn);
String text;
for (int i = 0; i < 10; i++) {
text = "L" + i;
viewtexts.add(text);
}
mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);
mGroup.setGroupClickListener(this);
mSubmitBtn.setOnClickListener(this);
super.onCreate(savedInstanceState);
}
@Override
public void onGroupItemClick(int item) {
chooseID = item;
chooseText = mGroup.getChooseText(item);
}
@Override
public void onClick(View view) {
if (chooseID >= 0) {
showToast("ID:" + chooseID + ";text:" + chooseText);
} else {
showToast("請(qǐng)選擇");
}
}
private void showToast(String text) {
Toast.makeText(ButtonGroupActivity.this, text, Toast.LENGTH_SHORT).show();
}
}
activity_buttongroup.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linear_ayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.jisuanqi.GoodsViewGroup android:id="@+id/viewGroup" android:layout_width="match_parent" android:layout_height="wrap_content"> </com.example.jisuanqi.GoodsViewGroup> <Button android:id="@+id/submitBtn" android:text="確定" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
總結(jié)
以上就是關(guān)于Android實(shí)現(xiàn)淘寶選中商品不同尺寸的按鈕組的全部?jī)?nèi)容了,如果本文有什么問(wèn)題歡迎大家指出,大家共同進(jìn)步!希望本文對(duì)大家的學(xué)習(xí)和工作能有所幫助哦~
- Android仿美團(tuán)下拉菜單(商品選購(gòu))實(shí)例代碼
- Android實(shí)現(xiàn)仿淘寶購(gòu)物車(chē)增加和減少商品數(shù)量功能demo示例
- Android仿淘寶商品瀏覽界面圖片滾動(dòng)效果
- Android 仿淘寶、京東商品詳情頁(yè)向上拖動(dòng)查看圖文詳情控件DEMO詳解
- Android把商品添加到購(gòu)物車(chē)的動(dòng)畫(huà)效果(貝塞爾曲線)
- Android自定義商品購(gòu)買(mǎi)數(shù)量加減控件
- 安卓(android)仿電商app商品詳情頁(yè)按鈕浮動(dòng)效果
- Android 仿京東、拼多多商品分類(lèi)頁(yè)的示例代碼
- Android 仿淘寶商品屬性標(biāo)簽頁(yè)
- android仿京東商品屬性篩選功能
相關(guān)文章
Android調(diào)用系統(tǒng)的發(fā)郵件功能的小例子
這篇文章介紹了Android調(diào)用系統(tǒng)的發(fā)郵件功能的小例子,有需要的朋友可以參考一下2013-08-08
Android JNI c/c++調(diào)用java的實(shí)例
這篇文章主要介紹了Android JNI c/c++調(diào)用java的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-07-07
Android將Xamarin For VS升級(jí)為4.1.0.530版教程
這篇文章主要介紹了Android將Xamarin For VS升級(jí)為4.1.0.530版的圖文教程,感興趣的小伙伴們可以參考一下2016-06-06
詳解Android數(shù)據(jù)存儲(chǔ)—使用SQLite數(shù)據(jù)庫(kù)
本篇文章主要介紹了詳解Android數(shù)據(jù)存儲(chǔ)—使用SQLite數(shù)據(jù)庫(kù),具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
Android使用Activity實(shí)現(xiàn)簡(jiǎn)單的可輸入對(duì)話框
大家在做彈出對(duì)話框效果的時(shí)候最容易想到的是用Dialog顯示,但其實(shí)彈出對(duì)話框的實(shí)現(xiàn)效果有兩種:Dialog和Activity,那么下面這篇文章就來(lái)給大家介紹了關(guān)于Android使用Activity如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的可輸入對(duì)話框的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-10-10
Android開(kāi)發(fā)實(shí)現(xiàn)撥打電話與發(fā)送信息的方法分析
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)撥打電話與發(fā)送信息的方法,結(jié)合實(shí)例形式分析了Android撥打電話及發(fā)送信息相關(guān)布局、功能實(shí)現(xiàn)及權(quán)限控制操作技巧,需要的朋友可以參考下2017-12-12
a2sd+狀態(tài)下應(yīng)用程序丟失的解決方法詳細(xì)解析
用了a2sd+和SD分區(qū)方案的朋友可能會(huì)遇到突然某次開(kāi)機(jī)之后,a2sd+失效,同時(shí)發(fā)生丟失若干應(yīng)用程序的現(xiàn)象或者安裝軟件提示空間不足2013-09-09
android中ProgressDialog與ProgressBar的使用詳解
本篇文章是對(duì)android中ProgressDialog與ProgressBar的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
在Android中創(chuàng)建菜單項(xiàng)Menu以及獲取手機(jī)分辨率的解決方法
本篇文章小編為大家介紹,在Android中創(chuàng)建菜單項(xiàng)Menu以及獲取手機(jī)分辨率的解決方法。需要的朋友參考下2013-04-04

