Android實(shí)現(xiàn)淘寶選中商品尺寸的按鈕組實(shí)例
話(huà)不多說(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
的話(huà),這里也設(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à)效果(貝塞爾曲線(xiàn))
- Android自定義商品購(gòu)買(mǎi)數(shù)量加減控件
- 安卓(android)仿電商app商品詳情頁(yè)按鈕浮動(dòng)效果
- Android 仿京東、拼多多商品分類(lèi)頁(yè)的示例代碼
- Android 仿淘寶商品屬性標(biāo)簽頁(yè)
- android仿京東商品屬性篩選功能
相關(guān)文章
Android中 webView調(diào)用JS出錯(cuò)的解決辦法
這篇文章主要介紹了Android中 webView調(diào)用JS出錯(cuò)的解決辦法,需要的朋友可以參考下2015-01-01Android游戲開(kāi)發(fā)之碰撞檢測(cè)(矩形碰撞、圓形碰撞、像素碰撞)
這篇文章主要介紹了Android游戲開(kāi)發(fā)之碰撞檢測(cè),主要內(nèi)容包含矩形碰撞、圓形碰撞、像素碰撞、多矩形碰撞的代碼,感興趣的小伙伴們可以參考一下2016-07-07Android Studio出現(xiàn)Failed to pull selection: open failed: Permi
本篇文章給大家分享了Android Studio中導(dǎo)出數(shù)據(jù)庫(kù)文件的方法以及出現(xiàn)Failed to pull selection: open failed: Permission denied的解決思路,有興趣的學(xué)習(xí)下。2018-05-05Kotlin使用滾動(dòng)控件RecyclerView實(shí)例教程
RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動(dòng),也可以實(shí)現(xiàn)橫向滾動(dòng)(ListView做不到橫向滾動(dòng))。接下來(lái)講解RecyclerView的用法2022-12-12Android開(kāi)發(fā)MQTT協(xié)議的模型及通信淺析
這篇文章主要W為大家介紹了Android開(kāi)發(fā)MQTT協(xié)議的模型及通信淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Android 按后退鍵退出Android程序的實(shí)現(xiàn)方法
本篇文章介紹了,在Android中按后退鍵退出Android程序的實(shí)現(xiàn)方法。需要的朋友參考下2013-04-04Android開(kāi)發(fā)中WebView的簡(jiǎn)單使用小結(jié)
WebView(網(wǎng)絡(luò)視圖)能加載顯示網(wǎng)頁(yè),可以將其視為一個(gè)瀏覽器。它使用了WebKit渲染引擎加載顯示網(wǎng)頁(yè)。下面這篇文章給大家總結(jié)了Android中WebView的簡(jiǎn)單使用,有需要的可以參考借鑒。2016-09-09Android ViewPager實(shí)現(xiàn)輪播圖效果
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實(shí)現(xiàn)輪播圖效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02Android開(kāi)發(fā)之TableLayout表格布局
這篇文章主要為大家詳細(xì)介紹了Android開(kāi)發(fā)之TableLayout表格布局,表格布局模型是以行列的形式管理子控件,對(duì)TableLayout表格布局感興趣的小伙伴們可以參考一下2016-03-03Android實(shí)現(xiàn)上傳文件到服務(wù)器實(shí)例詳解
本篇文章詳細(xì)介紹了Android實(shí)現(xiàn)上傳文件到服務(wù)器實(shí)例詳解,實(shí)現(xiàn)了文件每隔5秒進(jìn)行上傳,有需要的可以了解一下。2016-11-11