1. 程式人生 > >Android 自定義標籤選擇按鈕組(一)

Android 自定義標籤選擇按鈕組(一)

效果圖:

一、原理:

1.其實這裡我們用到的是一個ViewGroup控制元件組,把這些按鈕加進去就有這種效果了!不過這裡要繼承ViewGroup(命名為:GoodsViewGroup)重寫裡面的一些方法。

2.主要的方法有:

GoodsViewGroup按鈕組的控制元件大小

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

裡面的按鈕每個的位置座標

protected void onLayout(boolean changed, int l, int t, int r, int b) 


這兩個方法的具體使用大家可以網上查閱資料,這裡就不多說了!

二、程式碼:

/**
 * Created by ShaoLin on 2016/8/22.
 * 這裡是類似淘寶中商品尺寸按鈕組(這裡做了支援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 = 50;    //水平間隔
    private final int VerInterval = 20;    //垂直間隔

    private int viewWidth;   //控制元件的寬度
    private int viewHeight;  //控制元件的高度

    private ArrayList<String> mTexts = new ArrayList<>();
    private Context mContext;
    private int textModePadding = 30;

    private int textModePaddingLeft = 50;
    private int textModePaddingTop = 25;
    private int textModePaddingRight = 50;
    private int textModePaddingBottom = 25;

    //正常樣式
    private float itemTextSize = 12;
    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;
    }

    /**
     * 計算控制元件的大小
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = measureWidth(widthMeasureSpec);
        viewHeight = measureHeight(heightMeasureSpec);
        Log.e(TAG, "onMeasure:" + viewWidth + ":" + viewHeight);
        // 計算自定義的ViewGroup中所有子控制元件的大小
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        // 設定自定義的控制元件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是精確尺寸,
             * 當我們將控制元件的layout_width或layout_height指定為具體數值時如andorid
             * :layout_width="50dip",或者為FILL_PARENT是,都是控制元件大小已經確定的情況,都是精確尺寸。
             *
             *
             * MeasureSpec.AT_MOST是最大尺寸,
             * 當控制元件的layout_width或layout_height指定為WRAP_CONTENT時
             * ,控制元件大小一般隨著控制元件的子空間或內容進行變化,此時控制元件尺寸只要不超過父控制元件允許的最大尺寸即可
             * 。因此,此時的mode是AT_MOST,size給出了父控制元件允許的最大尺寸。
             *
             *
             * MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控制元件是AdapterView,
             * 通過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;
    }

    /**
     * 覆寫onLayout,其目的是為了指定檢視的顯示位置,方法執行的前後順序是在onMeasure之後,因為檢視肯定是隻有知道大小的情況下,
     * 才能確定怎麼擺放
     */
    @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中計算的檢視尺寸
            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);
        }
    }

    /**
     * 獲取控制元件的自適應高度
     *
     * @return
     */
    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中計算的檢視尺寸
            int measureHeight = childView.getMeasuredHeight();
            int measuredWidth = childView.getMeasuredWidth();
            //------------當前按鈕按鈕是否在水平上夠位置(2017/7/10)------------
            if (viewwidth + getNextHorLastPos(i) > viewWidth) {
                //------------修正沒有計算所在行第一個所需寬度(2017/7/10)------------
                viewwidth = (measuredWidth + HorInterval * 2);
                viewheight += (measureHeight + VerInterval);
            } else {
                viewwidth += (measuredWidth + HorInterval);
            }
        }
        return viewheight;
    }
    /**
     * 當前按鈕所需的寬度
     * @param i
     * @return
     */
    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);
                }
            });
        }
    }

    //選中那個的樣式
    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(textModePaddingLeft, textModePaddingTop, textModePaddingRight, textModePaddingBottom);
        }
    }

    //清除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);
    }
}

上面提供了可以設定按鈕組的item的一些樣式,還有這個GoodsViewGroup為什麼要寫成GoodsViewGroup<X extends TextView>這樣呢?其實這裡我是想做一個泛型,可以使用與Button跟TextView,而這裡的Button本生就是繼承TextView所以在程式碼中還要進行一個判斷,可以看上面方法setItemPadding(X view)。那到了這裡,有些好友可能就會問,為什麼要搞兩個呢?

其實這裡因為TextView的不會自動有設定padding的,而button是有自動設定padding。這個時候你就要看看你是先要那種效果!不過通過我的程式碼中如果是選擇TextView的話,這裡也設定了一個padding給他,不然會很難看!

兩種模式的寫法:

1.Button :

GoodsViewGroup<Button> mGroup;
mGroup.addItemViews(viewtexts, GoodsViewGroup.BTN_MODE);

2.TextView

GoodsViewGroup<TextView> mGroup;
mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);

三、Drawable檔案:上面涉及到的按鈕選中與正常的兩個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="15dp" />
        </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="@color/colorAccent" />
            <corners android:radius="15dp" />
        </shape>
    </item>
</layer-list>

四、例子:

final ArrayList<String> viewtexts = new ArrayList<>();
viewtexts.add("基礎資訊");
viewtexts.add("通訊資訊");
viewtexts.add("後備電源");
headViewHolde.viewGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);
headViewHolde.viewGroup.chooseItemStyle(0);
headViewHolde.viewGroup.setGroupClickListener(new GoodsViewGroup.OnGroupItemClickListener() {
    @Override
    public void onGroupItemClick(int item) {
        Toast.makeText(mContext, viewtexts.get(item), Toast.LENGTH_SHORT).show();
    }
});

xml頁面

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:layout_marginTop="10dp"
    android:orientation="vertical">

    <com.distributionsysten.view.GoodsViewGroup
        android:id="@+id/viewGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="10dp">
    </com.distributionsysten.view.GoodsViewGroup>

</LinearLayout>

相關推薦

Android 定義標籤選擇按鈕

效果圖: 一、原理: 1.其實這裡我們用到的是一個ViewGroup控制元件組,把這些按鈕加進去就有這種效果了!不過這裡要繼承ViewGroup(命名為:GoodsViewGroup)重寫裡面的一些方法。 2.主要的方法有: GoodsViewGroup按鈕組

Android 定義標籤選擇按鈕

GoodsViewGroup修改與完善有以下幾點: 一、這裡就只支援TextView模式,以為在Button模式下,padding設定比其預設的更小時是看不到作用的,所以做了修整 二、新增GoodsViewGroupItem裡面有key跟value兩個欄位,使用者在這裡可

Android-定義影象資源的使用1

Android-自定義影象資源的使用2014年4月28日 週一 天氣晴朗 心情平靜有興趣的朋友可以加本人建立的群,裡面有豐富的學習資源哦:299402133(移動開發狂熱者群)Android中有以下幾種

Android定義控制元件開發系列——仿支付寶六位支付密碼輸入頁面

        在移動互聯領域,有那麼幾家龍頭一直是我等學習和追求的目標,比如支付寶、微信、餓了麼、酷狗音樂等等,大神舉不勝舉,他們設計的介面、互動方式已經培養了中國(有可能會是世界)民眾的操作習慣:舉個小例子,對話方塊“確定”按鈕的左右位置就很有學問,如果大家都是左邊取消

html定義單選按鈕radioCSS

最近需要自定義radio,參考了一些別人的文章,在這裡記錄一下自己做的一個小選擇頁面。 效果圖如下:(點選按鈕前) 點選按鈕並選擇後:  顏色大小等都可以根據專案進行修改,這裡為了介面的好看,對span整個Div左浮動,選擇項右浮動。為了分割開選項,採取了給按鈕

android定義View,實現折線圖

效果圖: LineChartView類: public class LineChartView extends View { private int width; private int height; private float maxVal

Docker之定義映象製作與執行

     前幾篇我們介紹了Windows下安裝Docker與第三方Nginx映象執行,這一篇我們學習怎麼自己製作映象並放在docker容器中執行起來。製作映象     製作映象首先要知道你這個專案所要依賴什麼環境下才能執行,我們的專案都是JAVA WEB專案,所以就要依賴to

怎樣為std::map的定義key提供比較操作

  stl的關聯容器(map,set)的key一般要求提供 < 比較操作。假設我們有一個結構SomeKey: struct SomeKey { int a, b; };   要想以SomeKey作為std::map的key,需要為這個結構提

Mybatis-generator修改原始碼實現定義方法,返回List物件

Mybatis-generator修改原始碼實現自定義方法,返回Lsit物件——第一篇 本文結合網上的諸多教程,詳細介紹通過修改Mybatis-generator的原始碼, 在自動生成dao層和XML檔案時,新增一個返回List的方法,資料庫使用Mysql

android--------定義視頻控件視頻全屏豎屏自動切換

github get src color href 橫豎屏切換 圖片 div 分享 android播放視頻也是常用的技術,今天分享一個自定義視頻控件,支持自定義控制 UI,全屏播放, 可以實現自動橫豎屏切換的控件,跟隨手機的位置而,重力感應自動切換橫豎屏. 效果圖:

按鈕配置之定義按鈕使用——JEPLUS軟件快速開發平臺

事件 proc oss In 需求 信息 ces otto 圖片 JEPLUS按鈕配置之自定義按鈕使用(一)系統開發過程中無論是表單的默認按鈕或是列表的默認按鈕以及Action的默認按鈕有時候並不能滿足我們的業務需求,這個時

CSS定義select選擇框樣式右側下拉箭頭

如圖:自定義select的箭頭樣式  HTML以及CSS程式碼如下: <select class="form_select"> <option value="0">請選擇</option> <option value=

【舉例】Android定義Dialog——選擇一個RadioButton

1. 自定義Dialog的介面 <--!dialog_selectserver.xml--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://sch

Android定義標籤列表控制元件LabelsView

無論是在移動端的App,還是在前端的網頁,我們經常會看到下面這種標籤的列表效果: 標籤從左到右擺放,一行顯示不下時自動換行。這樣的效果用Android源生的控制元件很不好實現,所以往往需要我們自己去自定義控制元件。我在開發中就遇到過幾次要實現這樣的標籤列表效果,所以就自己寫了個控制元件,放到我的

Android 定義數字選擇器,可以根據自己的需求更改

實現效果如下: 還是以往的套路,先把那些專案所需要的給展示出來。 values下的資料夾,attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styl

Android 定義帶刪除按鈕的EditText

首先建立一個類 設定成EditTextWithDel,繼承EditText。 實現程式碼如下。 @SuppressLint("AppCompatCustomView") public class EditTextWithDel extends EditText { priv

Android定義主題樣式詳解結合定義title欄講解

此篇部落格將總結主題樣式的自定義並且結合例項自定義title欄進行講解。為了方便閱讀,在此先寫明文章結構: 1.對android主題樣式的理解 (簡略結合系統自帶樣式的講解) 2.如何自定義主題樣式 (主要,有例子) 3.如何自定義titl

Android應用中使用定義證書的HTTPS連線

因為這部分才是本文的重點,要說得詳細一點,所以單獨做成一篇來說。安全地使用自定義證書的HTTPS連線方式終極解決方案是:把證書編譯到應用中去,由應用自己來驗證證書。生成KeyStore要驗證自定義證書,首先要把證書編譯到應用中去,這需要JSSE提供的keytool工具來生成K

定義時間選擇控制元件仿ios滾動效果

1.先上自定義的控制元件: /** * 滾輪選擇器 * author LH * data 2016/8/20 17:26 */ public class WheelView extends View { public static final String

Android定義時間選擇器或者WheelView

public class PickView extends View{ public static final String TAG = "PickerView"; /** * text之間間距和minTextSize之比 */ publ