關于RadioButton排列的問題

記錄項目中遇到的問題

今天項目遇到這樣一個需求:radiobutton 排版為2行2列缚柳,然而radiogroup繼承自 LinearLayout 原始的控件僅支持水平排列,或垂直排列。然而這并不能滿足需求衣摩。于是在網(wǎng)上找了大量的例子苹丸。最終還是用自己方法實現(xiàn)了需求侥蒙。
在此記錄不要直接看代碼

先上圖

預覽圖.png

網(wǎng)上的方法

  • 1哄褒、通過設置readiobutton 的margin值為負值來進行排版
  • 2兴猩、通過自定義radiogroup 重點重寫addView 從viewGroup里面直接取出里面的radiobutton

我的方法最diao

重點解說

前兩種沒啥說的焰檩,網(wǎng)上都是說的這兩種,只是形式不同订框。
這里只記錄我的方法
第一步:負值radiogroup源碼到到你新建的類里面
第二步:radiogroup繼承與Linerlayout改成RelativeLayout
第三步:將報錯的相關部分刪掉析苫,將setOnCheckedChangeWidgetListener替換成setOnCheckedChangeListener
最后:拿去盡情的布局吧


代碼:
這是自定義的radioGroup 可拿去直接用

package com.liumeng.radiogroup.view;/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.IdRes;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RelativeLayout;


public class LiumRadioGroup extends RelativeLayout {
   // holds the checked id; the selection is empty by default
   private int mCheckedId = -1;
   // tracks children radio buttons checked state
   private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
   // when true, mOnCheckedChangeListener discards events
   private boolean mProtectFromCheckedChange = false;
   private OnCheckedChangeListener mOnCheckedChangeListener;
   private PassThroughHierarchyChangeListener mPassThroughListener;

   /**
    * {@inheritDoc}
    */
   public LiumRadioGroup(Context context) {
       super(context);
       init();
   }

   /**
    * {@inheritDoc}
    */
   public LiumRadioGroup(Context context, AttributeSet attrs) {
       super(context, attrs);
       init();
   }

   private void init() {
       mChildOnCheckedChangeListener = new CheckedStateTracker();
       mPassThroughListener = new PassThroughHierarchyChangeListener();
       super.setOnHierarchyChangeListener(mPassThroughListener);
   }

   /**
    * {@inheritDoc}
    */
   @Override
   public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
       // the user listener is delegated to our pass-through listener
       mPassThroughListener.mOnHierarchyChangeListener = listener;
   }

   /**
    * {@inheritDoc}
    */
   @Override
   protected void onFinishInflate() {
       super.onFinishInflate();

       // checks the appropriate radio button as requested in the XML file
       if (mCheckedId != -1) {
           mProtectFromCheckedChange = true;
           setCheckedStateForView(mCheckedId, true);
           mProtectFromCheckedChange = false;
           setCheckedId(mCheckedId);
       }
   }


   @Override
   public void addView(View child, int index, ViewGroup.LayoutParams params) {
       if (child instanceof RadioButton) {
           final RadioButton button = (RadioButton) child;
           if (button.isChecked()) {
               mProtectFromCheckedChange = true;
               if (mCheckedId != -1) {
                   setCheckedStateForView(mCheckedId, false);
               }
               mProtectFromCheckedChange = false;
               setCheckedId(button.getId());
           }
       }

       super.addView(child, index, params);
   }

   /**
    * <p>Sets the selection to the radio button whose identifier is passed in
    * parameter. Using -1 as the selection identifier clears the selection;
    * such an operation is equivalent to invoking {@link #clearCheck()}.</p>
    *
    * @param id the unique id of the radio button to select in this group
    * @see #getCheckedRadioButtonId()
    * @see #clearCheck()
    */
   public void check(@IdRes int id) {
       // don't even bother
       if (id != -1 && (id == mCheckedId)) {
           return;
       }

       if (mCheckedId != -1) {
           setCheckedStateForView(mCheckedId, false);
       }

       if (id != -1) {
           setCheckedStateForView(id, true);
       }

       setCheckedId(id);
   }

   private void setCheckedId(@IdRes int id) {
       mCheckedId = id;
       if (mOnCheckedChangeListener != null) {
           mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
       }
   }

   private void setCheckedStateForView(int viewId, boolean checked) {
       View checkedView = findViewById(viewId);
       if (checkedView != null && checkedView instanceof RadioButton) {
           ((RadioButton) checkedView).setChecked(checked);
       }
   }

   /**
    * <p>Returns the identifier of the selected radio button in this group.
    * Upon empty selection, the returned value is -1.</p>
    *
    * @return the unique id of the selected radio button in this group
    * @attr ref android.R.styleable#RadioGroup_checkedButton
    * @see #check(int)
    * @see #clearCheck()
    */
   @IdRes
   public int getCheckedRadioButtonId() {
       return mCheckedId;
   }

   /**
    * <p>Clears the selection. When the selection is cleared, no radio button
    * in this group is selected and {@link #getCheckedRadioButtonId()} returns
    * null.</p>
    *
    * @see #check(int)
    * @see #getCheckedRadioButtonId()
    */
   public void clearCheck() {
       check(-1);
   }

   /**
    * <p>Register a callback to be invoked when the checked radio button
    * changes in this group.</p>
    *
    * @param listener the callback to call on checked state change
    */
   public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
       mOnCheckedChangeListener = listener;
   }

   /**
    * {@inheritDoc}
    */
   @Override
   public RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
       return new LiumRadioGroup.LayoutParams(getContext(), attrs);
   }

   /**
    * {@inheritDoc}
    */
   @Override
   protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
       return p instanceof LiumRadioGroup.LayoutParams;
   }

   @Override
   protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
       return new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
   }

   @Override
   public CharSequence getAccessibilityClassName() {
       return LiumRadioGroup.class.getName();
   }

   /**
    * <p>Interface definition for a callback to be invoked when the checked
    * radio button changed in this group.</p>
    */
   public interface OnCheckedChangeListener {
       /**
        * <p>Called when the checked radio button has changed. When the
        * selection is cleared, checkedId is -1.</p>
        *
        * @param group     the group in which the checked radio button has changed
        * @param checkedId the unique identifier of the newly checked radio button
        */
       public void onCheckedChanged(LiumRadioGroup group, @IdRes int checkedId);
   }

   /**
    * <p>This set of layout parameters defaults the width and the height of
    * the children to {@link #WRAP_CONTENT} when they are not specified in the
    * XML file. Otherwise, this class ussed the value read from the XML file.</p>
    * <p>
    * <p>See
    * for a list of all child view attributes that this class supports.</p>
    */
   public static class LayoutParams extends RelativeLayout.LayoutParams {
       /**
        * {@inheritDoc}
        */
       public LayoutParams(Context c, AttributeSet attrs) {
           super(c, attrs);
       }

       /**
        * {@inheritDoc}
        */
       public LayoutParams(int w, int h) {
           super(w, h);
       }

       /**
        * {@inheritDoc}
        */
       public LayoutParams(int w, int h, float initWeight) {
           super(w, h);
       }

       /**
        * {@inheritDoc}
        */
       public LayoutParams(ViewGroup.LayoutParams p) {
           super(p);
       }

       /**
        * {@inheritDoc}
        */
       public LayoutParams(MarginLayoutParams source) {
           super(source);
       }

       /**
        * <p>Fixes the child's width to
        * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the child's
        * height to  {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
        * when not specified in the XML file.</p>
        *
        * @param a          the styled attributes set
        * @param widthAttr  the width attribute to fetch
        * @param heightAttr the height attribute to fetch
        */
       @Override
       protected void setBaseAttributes(TypedArray a,
                                        int widthAttr, int heightAttr) {

           if (a.hasValue(widthAttr)) {
               width = a.getLayoutDimension(widthAttr, "layout_width");
           } else {
               width = WRAP_CONTENT;
           }

           if (a.hasValue(heightAttr)) {
               height = a.getLayoutDimension(heightAttr, "layout_height");
           } else {
               height = WRAP_CONTENT;
           }
       }
   }

   private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
           // prevents from infinite recursion
           if (mProtectFromCheckedChange) {
               return;
           }

           mProtectFromCheckedChange = true;
           if (mCheckedId != -1) {
               setCheckedStateForView(mCheckedId, false);
           }
           mProtectFromCheckedChange = false;

           int id = buttonView.getId();
           setCheckedId(id);
       }
   }

   /**
    * <p>A pass-through listener acts upon the events and dispatches them
    * to another listener. This allows the table layout to set its own internal
    * hierarchy change listener without preventing the user to setup his.</p>
    */
   private class PassThroughHierarchyChangeListener implements
           ViewGroup.OnHierarchyChangeListener {
       private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;

       /**
        * {@inheritDoc}
        */
       public void onChildViewAdded(View parent, View child) {
           if (parent == LiumRadioGroup.this && child instanceof RadioButton) {
               int id = child.getId();
               // generates an id if it's missing
               if (id == View.NO_ID) {
                   id = View.generateViewId();
                   child.setId(id);
               }
               ((RadioButton) child).setOnCheckedChangeListener(
                       mChildOnCheckedChangeListener);
           }

           if (mOnHierarchyChangeListener != null) {
               mOnHierarchyChangeListener.onChildViewAdded(parent, child);
           }
       }

       /**
        * {@inheritDoc}
        */
       public void onChildViewRemoved(View parent, View child) {
           if (parent == LiumRadioGroup.this && child instanceof RadioButton) {
               ((RadioButton) child).setOnCheckedChangeListener(null);
           }

           if (mOnHierarchyChangeListener != null) {
               mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
           }
       }
   }
}

布局文件展示?

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.moppomobi.test.view.LiumRadioGroup
        android:id="@+id/rg"
        android:layout_width="match_parent"
        android:layout_height="500dp">

        <RadioButton
            android:id="@+id/radioButton1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="RadioButton1" />

        <RadioButton
            android:id="@+id/radioButton2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toEndOf="@+id/radioButton1"
            android:text="RadioButton2" />

        <RadioButton
            android:id="@+id/radioButton3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/radioButton1"
            android:text="RadioButton3" />

        <RadioButton
            android:id="@+id/radioButton4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/radioButton2"
            android:layout_toEndOf="@id/radioButton3"
            android:text="RadioButton4" />


    </com.moppomobi.test.view.LiumRadioGroup>


</LinearLayout>

歡迎轉(zhuǎn)載,注明出處(不知道有啥用穿扳,但是人家都這么說了)http://www.reibang.com/p/5de08d69c02e

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衩侥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子矛物,更是在濱河造成了極大的恐慌茫死,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件履羞,死亡現(xiàn)場離奇詭異峦萎,居然都是意外死亡,警方通過查閱死者的電腦和手機忆首,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門爱榔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雄卷,你說我怎么就攤上這事搓蚪。” “怎么了丁鹉?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵妒潭,是天一觀的道長。 經(jīng)常有香客問我揣钦,道長雳灾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任冯凹,我火速辦了婚禮谎亩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宇姚。我一直安慰自己匈庭,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布浑劳。 她就那樣靜靜地躺著阱持,像睡著了一般。 火紅的嫁衣襯著肌膚如雪魔熏。 梳的紋絲不亂的頭發(fā)上衷咽,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天鸽扁,我揣著相機與錄音,去河邊找鬼镶骗。 笑死桶现,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鼎姊。 我是一名探鬼主播骡和,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼相寇!你這毒婦竟也來了即横?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤裆赵,失蹤者是張志新(化名)和其女友劉穎东囚,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體战授,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡页藻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了植兰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片份帐。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖楣导,靈堂內(nèi)的尸體忽然破棺而出废境,到底是詐尸還是另有隱情,我是刑警寧澤筒繁,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布噩凹,位于F島的核電站,受9級特大地震影響毡咏,放射性物質(zhì)發(fā)生泄漏驮宴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一呕缭、第九天 我趴在偏房一處隱蔽的房頂上張望堵泽。 院中可真熱鬧,春花似錦恢总、人聲如沸迎罗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纹安。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钻蔑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工奸鸯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留咪笑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓娄涩,卻偏偏與公主長得像窗怒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蓄拣,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評論 25 707
  • 最近有一個需求扬虚,需要實現(xiàn)單選的功能,類似這個 像這種結(jié)構球恤,通過RecyclerView,FlexBoxLayout...
    鋒ivy閱讀 3,728評論 5 15
  • 時間:2016年5月24日16:44:21作者:JustDo23說明:在開發(fā)中經(jīng)常會遇到使用Fragment的情況...
    JustDo23閱讀 972評論 0 3
  • 在來北方以前辜昵,我一直以為北方是一種“北國風光,千里冰封咽斧,萬里雪飄”的雄壯情懷堪置,當然,也以為是極為寒冷的张惹。 在來到了...
    梅花_Lu閱讀 487評論 0 0
  • 這樣的姿勢才正確 1舀锨、只字不差地閱讀 很多人追求閱讀得快和閱讀量。各大公眾號推崇類似的口號:每天一本書宛逗,一年365...
    大人黃桃閱讀 190評論 0 1