`

不带布局的RadioGroup——NoLayoutRadioGroup

 
阅读更多

虽然android的源码也时不时的会去看,但大部分还是只能看懂部分。这里只把能完全看懂的源码上传了。 

android.widget.AnalogClock 
这个类比较简单,如果想要创建自己的View,可以从参考这个类开始。像TextView这种将近一万行的源码就太多了。还有一个比这个稍微难一点的是ImageView,也可以看那个类 

Java代码  收藏代码
  1. public class AnalogClock extends View {  
  2.     private Time mCalendar;  
  3.       
  4.     /** 时针背景 */  
  5.     private Drawable mHourHand;  
  6.     /** 分针背景 */  
  7.     private Drawable mMinuteHand;  
  8.     /** 表盘背景 */  
  9.     private Drawable mDial;  
  10.       
  11.     /** 表盘宽度 */  
  12.     private int mDialWidth;  
  13.     /** 表盘高度 */  
  14.     private int mDialHeight;  
  15.   
  16.     /** 是否添加到WindowManager中 */  
  17.     private boolean mAttached;  
  18.   
  19.     private final Handler mHandler = new Handler();  
  20.     private float mMinutes;  
  21.     private float mHour;  
  22.     /** 时间是否改变了 */  
  23.     private boolean mChanged;  
  24.   
  25.     public AnalogClock(Context context) {  
  26.         this(context, null);  
  27.     }  
  28.   
  29.     public AnalogClock(Context context, AttributeSet attrs) {  
  30.         this(context, attrs, 0);  
  31.     }  
  32.   
  33.     public AnalogClock(Context context, AttributeSet attrs,  
  34.                        int defStyle) {  
  35.         super(context, attrs, defStyle);  
  36.         Resources r = mContext.getResources();  
  37.         TypedArray a =  
  38.                 context.obtainStyledAttributes(  
  39.                         attrs, com.android.internal.R.styleable.AnalogClock, defStyle, 0);  
  40.   
  41.         mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);  
  42.         if (mDial == null) {  
  43.             mDial = r.getDrawable(com.android.internal.R.drawable.clock_dial);  
  44.         }  
  45.   
  46.         mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);  
  47.         if (mHourHand == null) {  
  48.             mHourHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_hour);  
  49.         }  
  50.   
  51.         mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);  
  52.         if (mMinuteHand == null) {  
  53.             mMinuteHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_minute);  
  54.         }  
  55.   
  56.         mCalendar = new Time();  
  57.   
  58.         mDialWidth = mDial.getIntrinsicWidth();  
  59.         mDialHeight = mDial.getIntrinsicHeight();  
  60.     }  
  61.   
  62.     @Override  
  63.     protected void onAttachedToWindow() {  
  64.         super.onAttachedToWindow();  
  65.   
  66.         if (!mAttached) {  
  67.             mAttached = true;  
  68.             IntentFilter filter = new IntentFilter();  
  69.   
  70.             filter.addAction(Intent.ACTION_TIME_TICK);  
  71.             filter.addAction(Intent.ACTION_TIME_CHANGED);  
  72.             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);  
  73.   
  74.             getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);  
  75.         }  
  76.   
  77.         // NOTE: It's safe to do these after registering the receiver since the receiver always runs  
  78.         // in the main thread, therefore the receiver can't run before this method returns.  
  79.   
  80.         // The time zone may have changed while the receiver wasn't registered, so update the Time  
  81.         mCalendar = new Time();  
  82.   
  83.         // Make sure we update to the current time  
  84.         onTimeChanged();  
  85.     }  
  86.   
  87.     @Override  
  88.     protected void onDetachedFromWindow() {  
  89.         super.onDetachedFromWindow();  
  90.         if (mAttached) {  
  91.             getContext().unregisterReceiver(mIntentReceiver);  
  92.             mAttached = false;  
  93.         }  
  94.     }  
  95.   
  96.     @Override  
  97.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  98.   
  99.         int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  100.         // layout提供的可用Width  
  101.         int widthSize =  MeasureSpec.getSize(widthMeasureSpec);  
  102.         int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  103.         // layout提供的可用Height  
  104.         int heightSize =  MeasureSpec.getSize(heightMeasureSpec);  
  105.   
  106.         float hScale = 1.0f;  
  107.         float vScale = 1.0f;  
  108.   
  109.         // 如果layout_width和layout_height是指定了值的  
  110.         if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {  
  111.             hScale = (float) widthSize / (float) mDialWidth;  
  112.         }  
  113.   
  114.         if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {  
  115.             vScale = (float )heightSize / (float) mDialHeight;  
  116.         }  
  117.   
  118.         // 按照缩的比较小的缩放  
  119.         float scale = Math.min(hScale, vScale);  
  120.   
  121.         setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),  
  122.                 resolveSize((int) (mDialHeight * scale), heightMeasureSpec));  
  123.     }  
  124.   
  125.     @Override  
  126.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  127.         super.onSizeChanged(w, h, oldw, oldh);  
  128.         mChanged = true;  
  129.     }  
  130.   
  131.     @Override  
  132.     protected void onDraw(Canvas canvas) {  
  133.         super.onDraw(canvas);  
  134.   
  135.         boolean changed = mChanged;  
  136.         if (changed) {  
  137.             mChanged = false;  
  138.         }  
  139.   
  140.         int availableWidth = mRight - mLeft;  
  141.         int availableHeight = mBottom - mTop;  
  142.   
  143.         // 居中  
  144.         int x = availableWidth / 2;  
  145.         int y = availableHeight / 2;  
  146.   
  147.         final Drawable dial = mDial;  
  148.         int w = dial.getIntrinsicWidth();  
  149.         int h = dial.getIntrinsicHeight();  
  150.   
  151.         boolean scaled = false;  
  152.   
  153.         // 图片实际宽高比view的宽高大时,要对图片缩放  
  154.         if (availableWidth < w || availableHeight < h) {  
  155.             scaled = true;  
  156.             float scale = Math.min((float) availableWidth / (float) w,  
  157.                                    (float) availableHeight / (float) h);  
  158.             canvas.save();  
  159.             canvas.scale(scale, scale, x, y);  
  160.         }  
  161.   
  162.         if (changed) {  
  163.             dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));  
  164.         }  
  165.         dial.draw(canvas);  
  166.   
  167.         // 绘制时针  
  168.         canvas.save();  
  169.         canvas.rotate(mHour / 12.0f * 360.0f, x, y);  
  170.         final Drawable hourHand = mHourHand;  
  171.         if (changed) {  
  172.             w = hourHand.getIntrinsicWidth();  
  173.             h = hourHand.getIntrinsicHeight();  
  174.             hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));  
  175.         }  
  176.         hourHand.draw(canvas);  
  177.         canvas.restore();  
  178.   
  179.         // 绘制分针  
  180.         canvas.save();  
  181.         canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);  
  182.   
  183.         final Drawable minuteHand = mMinuteHand;  
  184.         if (changed) {  
  185.             w = minuteHand.getIntrinsicWidth();  
  186.             h = minuteHand.getIntrinsicHeight();  
  187.             minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));  
  188.         }  
  189.         minuteHand.draw(canvas);  
  190.         canvas.restore();  
  191.   
  192.         // 结束  
  193.         if (scaled) {  
  194.             canvas.restore();  
  195.         }  
  196.     }  
  197.   
  198.     private void onTimeChanged() {  
  199.         mCalendar.setToNow();  
  200.   
  201.         int hour = mCalendar.hour;  
  202.         int minute = mCalendar.minute;  
  203.         int second = mCalendar.second;  
  204.   
  205.         mMinutes = minute + second / 60.0f;  
  206.         mHour = hour + mMinutes / 60.0f;  
  207.         mChanged = true;  
  208.     }  
  209.   
  210.     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
  211.         @Override  
  212.         public void onReceive(Context context, Intent intent) {  
  213.             if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {  
  214.                 String tz = intent.getStringExtra("time-zone");  
  215.                 mCalendar = new Time(TimeZone.getTimeZone(tz).getID());  
  216.             }  
  217.   
  218.             onTimeChanged();  
  219.               
  220.             invalidate();  
  221.         }  
  222.     };  
  223. }  




不带布局的RadioGroup——NoLayoutRadioGroup 
android提供的RadioGroup是一个LinearLayout,有时我们要在像TableLayout中的每个行使用一个RadioButton的话,RadioGroup就不太好用,所以参考RadioGroup实现了一个不带布局的RadioGroup. 

Java代码  收藏代码
  1. /*** 
  2.  * 使用了这个类,RadioButton的OnCheckedChangeListener会被覆盖掉,所以 
  3.  * 要使用监听器的话,使用这边的NonLayoutRadioGroup.OnCheckedChangeListener 
  4.  */  
  5. public class NonLayoutRadioGroup {  
  6.     public interface OnCheckedChangeListener {  
  7.         /*** 
  8.          * @param group 触发该事件的NonLayoutRadioGroup 
  9.          * @param view 触发该事件的RadioButton, 当调用clearCheck时,view的值为null 
  10.          */  
  11.         public void onCheckedChanged(NonLayoutRadioGroup group, RadioButton view);  
  12.     }  
  13.       
  14.     private List<RadioButton> mRadioButtons = new ArrayList<RadioButton>();  
  15.       
  16.     private RadioButton mCheckButton;  
  17.       
  18.     private OnCheckedChangeListener mListener;  
  19.       
  20.     private CompoundButton.OnCheckedChangeListener mCheckedListener =  
  21.             new CompoundButton.OnCheckedChangeListener() {  
  22.         @Override  
  23.         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {  
  24.             if (!isChecked) {  
  25.                 mCheckButton = null;  
  26.                 return;  
  27.             }  
  28.             if (mCheckButton != null) {  
  29.                 mCheckButton.setChecked(false);  
  30.             }  
  31.               
  32.             setCheckedButton((RadioButton) buttonView);  
  33.         }  
  34.     };  
  35.       
  36.     public void addRadioButton(RadioButton button) {  
  37.         // 不能添加null  
  38.         // 为没有id的RadioButton生成一个Id  
  39.         if (button.getId() == View.NO_ID) {  
  40.             button.setId(button.hashCode());  
  41.         }  
  42.         button.setOnCheckedChangeListener(null);  
  43.         if (button.isChecked()) {  
  44.             // 移除原来的  
  45.             if (mCheckButton != null) {  
  46.                 mCheckButton.setChecked(false);  
  47.             }  
  48.               
  49.             setCheckedButton(button);  
  50.         }  
  51.         button.setOnCheckedChangeListener(mCheckedListener);  
  52.         mRadioButtons.add(button);  
  53.     }  
  54.       
  55.     public void removeRadioButton(RadioButton button) {  
  56.         // 添加到这里面的移除时,才需要清除其OnCheckedChangeListener  
  57.         if (mRadioButtons.contains(button)) {  
  58.             button.setOnCheckedChangeListener(null);  
  59.             mRadioButtons.remove(button);  
  60.         }  
  61.     }  
  62.       
  63.     public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {  
  64.         mListener = listener;  
  65.     }  
  66.       
  67.     public void check(RadioButton button) {  
  68.         // check原来选中的  
  69.         if (button != null && mCheckButton == button) {  
  70.             return;  
  71.         }  
  72.         // 移除选中的  
  73.         if (mCheckButton != null) {  
  74.             mCheckButton.setChecked(false);  
  75.         }  
  76.         // 设置选中的  
  77.         if (button != null) {  
  78.             button.setChecked(true);  
  79.         }  
  80.         // 触发监听器  
  81.         setCheckedButton(button);  
  82.     }  
  83.       
  84.     public void clearCheck() {  
  85.         check(null);  
  86.     }  
  87.       
  88.     public RadioButton getCheckedRadioButton() {  
  89.         return mCheckButton;  
  90.     }  
  91.       
  92.     // ////////////////////////////////////////////////  
  93.     /*** 
  94.      * 设置选中的RadioButton 
  95.      */  
  96.     private void setCheckedButton(RadioButton button) {  
  97.         mCheckButton = button;  
  98.         if (mListener != null) {  
  99.             if (button != null) {  
  100.                 mListener.onCheckedChanged(this, button);  
  101.             }  
  102.             else {  
  103.                 mListener.onCheckedChanged(thisnull);  
  104.             }  
  105.         }  
  106.     }  
  107. }  
分享到:
评论

相关推荐

    Android-支持多行多列等复杂布局的RadioGroup

    `Multi_RadioGroup_Plus`就是为了解决这一问题而设计的,它扩展了原生RadioGroup的功能,提供了更灵活的布局方式。 `Multi_RadioGroup_Plus`的核心特性包括: 1. **多行多列布局**:原生RadioGroup默认将...

    RadioGroup多列显示

    在这个主题中,我们将探讨如何在不重写RadioGroup的基础上,通过布局管理和样式调整来实现这一功能。 首先,我们需要理解RadioGroup的工作原理。RadioGroup本质上是一个线性布局(LinearLayout),它可以是垂直或...

    安卓Andriod源码——动态添加RadioGroup的RadioButton.zip

    这份"安卓Andriod源码——动态添加RadioGroup的RadioButton.zip"资源就提供了这样的示例代码,帮助开发者理解如何在运行时构建这些交互元素。 RadioGroup是Android中的一个布局容器,用于管理一组RadioButton。它...

    Android 自定义RadioGroup布局,修改源码自定义控件

    5. **自定义布局参数**:如果需要支持不同的布局类型,如网格布局,我们可以创建自定义的布局参数类,继承自`RadioGroup.LayoutParams`,并添加必要的属性来控制布局的样式。 6. **测试与优化**:完成自定义`...

    Android 自定义View实现任意布局的RadioGroup效果

    这使得在某些情况下,比如多行多列布局,RadioGroup 就并不适用。为了解决这个问题,开发者可以通过继承 RelativeLayout 实现自定义的 RadioGroup,从而实现 RadioButton 的任意布局。 自定义 RadioGroup 的实现...

    安卓Android源码——动态添加RadioGroup的RadioButton.zip

    RadioGroup是一种布局容器,用于管理一组RadioButton,使得同一时间只能有一个RadioButton被选中。 首先,我们需要了解基本的XML布局文件的创建。在Android应用中,通常会先定义一个基本的布局,如一个LinearLayout...

    换行的RadioGroup可以使用

    在Android开发中,`RadioGroup` 是一个非常常见的布局组件,用于管理一组单选按钮(RadioButton)。通常,`RadioGroup` 内的所有RadioButton是互斥的,用户只能选择其中一个。然而,标准的`RadioGroup`默认是水平...

    使用Fragment与RadioGroup实现页面布局切换

    而`RadioGroup`则是一种特殊的布局,用于管理一组单选按钮(RadioButton),用户只能选择其中一个按钮。 首先,让我们详细了解`Fragment`。`Fragment`的概念首次在Android 3.0(API级别11)引入,它使得在大屏幕...

    RadioGroup多行多列

    RadioGroup是一个线性布局容器,它会自动处理RadioButton之间的互斥关系,确保同一时间内只有一个RadioButton被选中。在XML布局文件中,你可以通过以下方式添加RadioGroup: ```xml &lt;RadioGroup android:id="@+...

    RadioGroup

    RadioGroup是一个布局容器,它可以包含一个或多个RadioButton。RadioGroup的主要作用是管理其内部的RadioButton,确保每次只能有一个RadioButton被选中。RadioGroup提供了点击事件监听和选中状态改变的回调,方便...

    RadioGroup自定义选项卡样式

    在Android开发中,RadioGroup是用于管理一组RadioButton的布局,它允许用户在多个选项中选择一个。本教程将深入探讨如何自定义RadioGroup以创建独特的选项卡样式,从而提升应用程序的用户体验。 首先,RadioGroup的...

    可多行的RadioGroup

    然而,标准的`RadioGroup`默认是水平排列的,这在选项过多时可能会导致一行显示不下,影响用户体验。针对这种情况,我们可以实现一个可多行显示的`RadioGroup`,这就是"可多行的RadioGroup"这一话题的核心。 首先,...

    重构RadioGroup

    但是,原生的`RadioGroup`并不支持自动换行,因此,我们不能简单地设置`orientation`属性来实现多列效果。 为了解决这个问题,我们可以创建一个新的自定义布局,继承自`RadioGroup`,并重写其中的部分方法。这个...

    使用RadioGroup与RadioButton

    1. **在XML布局中**:首先,在布局文件中创建一个`RadioGroup`,然后在其内部添加多个`RadioButton`。通过设置`android:layout_width`和`android:layout_height`控制`RadioButton`的大小,`android:text`设置文字...

    RadioGroup和RadioButton实现FragmentTabHost导航效果

    `RadioGroup`是一个布局容器,它可以包含多个`RadioButton`。`RadioGroup`的主要作用是管理其内部的`RadioButton`,确保每次只有一个`RadioButton`被选中。当用户点击`RadioButton`时,`RadioGroup`会自动取消其他`...

    Android学习笔记七:基本视图组件:RadioGroup和RadioButton

    RadioButton本身不能管理多个单选按钮之间的互斥关系,这就是RadioGroup的作用。 RadioGroup是一个容器组件,它可以包含多个RadioButton。当在一个RadioGroup中的RadioButton被点击时,RadioGroup会自动取消其他...

    Android中RadioGroup的作用与定义.pdf

    总之,RadioGroup是Android应用中不可或缺的一部分,它使得开发者能够轻松创建具有单选功能的界面,提高了用户体验。通过结合使用RadioButton和RadioGroup,开发者可以创建出各种各样的交互式表单和设置界面。了解和...

    RadioGroup实现底部导航页面

    RadioGroup是一个Android SDK提供的布局管理器,它允许我们在其中放置单选按钮(RadioButton),并且只允许选择其中一个。本篇文章将深入讲解如何使用RadioGroup和FrameLayout结合实现底部导航页面,并简单介绍工厂...

    用RadioGroup实现fragment的界面切换

    // 如果当前Fragment不存在,则添加到布局中 if (fragment == null) { // 创建新的Fragment实例 fragment = Fragment.getFragmentByTag(checkedId); // 添加到布局 transaction.add(R.id.container, fragment,...

Global site tag (gtag.js) - Google Analytics