Android Open Source - Material Radio Button Drawable






From Project

Back to project page Material.

License

The source code is released under:

Apache License

If you think the Android project Material listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.rey.material.drawable;
/* ww w  .  ja  v  a2 s .com*/
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.util.AttributeSet;

import com.rey.material.R;
import com.rey.material.util.ColorUtil;
import com.rey.material.util.ThemeUtil;
import com.rey.material.util.ViewUtil;

public class RadioButtonDrawable extends Drawable implements Animatable {
  
  private boolean mRunning = false;
  
  private Paint mPaint;
  
  private long mStartTime;
  private float mAnimProgress;
  private int mAnimDuration;
  private int mStrokeSize;
  private int mWidth;
  private int mHeight;
  private int mRadius;
  private int mInnerRadius;
  private int mPrevColor;
  private int mCurColor;
  private ColorStateList mStrokeColor;
  private boolean mChecked = false;  
  
  private boolean mInEditMode = false;
  private boolean mAnimEnable = true;
  
  private RadioButtonDrawable(int width, int height, int strokeSize, ColorStateList strokeColor, int radius, int innerRadius, int animDuration){
    mAnimDuration = animDuration;
    mStrokeSize = strokeSize;
    mWidth = width;
    mHeight = height;
    mRadius = radius;
    mInnerRadius = innerRadius;
    mStrokeColor = strokeColor;
    
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
  }
  
  public void setInEditMode(boolean b){
    mInEditMode = b;
  }
  
  public void setAnimEnable(boolean b){
    mAnimEnable = b;
  }
  
  public boolean isAnimEnable(){
    return mAnimEnable;
  }
  
  @Override
  public int getIntrinsicWidth() {
    return mWidth;
  }

  @Override
  public int getIntrinsicHeight() {
    return mHeight;
  }

  @Override
  public int getMinimumWidth() {
    return mWidth;
  }

  @Override
  public int getMinimumHeight() {
    return mHeight;
  }

  @Override
  public boolean isStateful() {
    return true;
  }
  
  @Override
  public void draw(Canvas canvas) {        
    if(mChecked)
      drawChecked(canvas);
    else
      drawUnchecked(canvas);
  }
    
  private void drawChecked(Canvas canvas){
    float cx = getBounds().exactCenterX();
    float cy = getBounds().exactCenterY();
    
    if(isRunning()){
      float halfStrokeSize = mStrokeSize / 2f;
      float inTime = (mRadius - halfStrokeSize) / (mRadius - halfStrokeSize + mRadius - mStrokeSize - mInnerRadius);
      
      if(mAnimProgress < inTime){
        float inProgress = mAnimProgress / inTime;        
        float outerRadius = mRadius + halfStrokeSize * (1f - inProgress);  
        float innerRadius = (mRadius - halfStrokeSize) * (1f - inProgress);
        
        mPaint.setColor(ColorUtil.getMiddleColor(mPrevColor, mCurColor, inProgress));
        mPaint.setStrokeWidth(outerRadius - innerRadius);
        mPaint.setStyle(Paint.Style.STROKE);          
        canvas.drawCircle(cx, cy, (outerRadius + innerRadius) / 2, mPaint);
      }
      else{
        float outProgress = (mAnimProgress - inTime) / (1f - inTime);        
        float innerRadius = (mRadius - mStrokeSize) * (1 - outProgress) + mInnerRadius * outProgress;  
        
        mPaint.setColor(mCurColor);
        mPaint.setStyle(Paint.Style.FILL);          
        canvas.drawCircle(cx, cy, innerRadius, mPaint);
        
        float outerRadius = mRadius + halfStrokeSize * outProgress;
        mPaint.setStrokeWidth(mStrokeSize);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(cx, cy, outerRadius - halfStrokeSize, mPaint);
      }      
    }
    else{
      mPaint.setColor(mCurColor);
      mPaint.setStrokeWidth(mStrokeSize);
      mPaint.setStyle(Paint.Style.STROKE);      
      canvas.drawCircle(cx, cy, mRadius, mPaint);
      
      mPaint.setStyle(Paint.Style.FILL);      
      canvas.drawCircle(cx, cy, mInnerRadius, mPaint);      
    }    
  }
  
  private void drawUnchecked(Canvas canvas){
    float cx = getBounds().exactCenterX();
    float cy = getBounds().exactCenterY();
    
    if(isRunning()){
      float halfStrokeSize = mStrokeSize / 2f;      
      float inTime = (mRadius - mStrokeSize - mInnerRadius) / (mRadius - halfStrokeSize + mRadius - mStrokeSize - mInnerRadius);
      
      if(mAnimProgress < inTime){
        float inProgress = mAnimProgress / inTime;
        float innerRadius = (mRadius - mStrokeSize) * inProgress + mInnerRadius * (1f - inProgress);
        
        mPaint.setColor(ColorUtil.getMiddleColor(mPrevColor, mCurColor, inProgress));
        mPaint.setStyle(Paint.Style.FILL);          
        canvas.drawCircle(cx, cy, innerRadius, mPaint);
        
        float outerRadius = mRadius + halfStrokeSize * (1f - inProgress);
        mPaint.setStrokeWidth(mStrokeSize);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(cx, cy, outerRadius - halfStrokeSize, mPaint);
      }
      else{
        float outProgress = (mAnimProgress - inTime) / (1f - inTime);        
        float outerRadius = mRadius + halfStrokeSize * outProgress;
        float innerRadius = (mRadius - halfStrokeSize) * outProgress;
        
        mPaint.setColor(mCurColor);
        mPaint.setStrokeWidth(outerRadius - innerRadius);
        mPaint.setStyle(Paint.Style.STROKE);          
        canvas.drawCircle(cx, cy, (outerRadius + innerRadius) / 2, mPaint);
      }
    }
    else{
      mPaint.setColor(mCurColor);
      mPaint.setStrokeWidth(mStrokeSize);
      mPaint.setStyle(Paint.Style.STROKE);      
      canvas.drawCircle(cx, cy, mRadius, mPaint);
    }
  }
  
  @Override
  protected boolean onStateChange(int[] state) {    
    boolean checked = ViewUtil.hasState(state, android.R.attr.state_checked);    
    int color = mStrokeColor.getColorForState(state, mCurColor);
    boolean needRedraw = false;
        
    if(mChecked != checked){
      mChecked = checked;
      needRedraw =  true;      
      if(!mInEditMode && mAnimEnable)
        start();
    }
        
    if(mCurColor != color){
      mPrevColor = isRunning() ? mCurColor : color;
      mCurColor = color;
      needRedraw = true;
    }
    else if(!isRunning())
      mPrevColor = color;  
    
    return needRedraw;
  }
  
  @Override
  public void setAlpha(int alpha) {
    mPaint.setAlpha(alpha);
  }

  @Override
  public void setColorFilter(ColorFilter cf) {
    mPaint.setColorFilter(cf);
  }

  @Override
  public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
  }
  
  //Animation: based on http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/
  
  private void resetAnimation(){  
    mStartTime = SystemClock.uptimeMillis();
    mAnimProgress = 0f;
  }
    
  @Override
  public void start() {      
    resetAnimation();
    
    scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION);
      invalidateSelf();  
  }

  @Override
  public void stop() {        
    mRunning = false;
    unscheduleSelf(mUpdater);
    invalidateSelf();
  }

  @Override
  public boolean isRunning() {
    return mRunning;
  }

  @Override
  public void scheduleSelf(Runnable what, long when) {
    mRunning = true;
      super.scheduleSelf(what, when);
  }
  
  private final Runnable mUpdater = new Runnable() {

      @Override
      public void run() {
        update();
      }
        
  };
    
  private void update(){
    long curTime = SystemClock.uptimeMillis();
    mAnimProgress = Math.min(1f, (float)(curTime - mStartTime) / mAnimDuration);
        
    if(mAnimProgress == 1f)
      mRunning = false;    
        
      if(isRunning())
        scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION);
      
      invalidateSelf();
  }

  public static class Builder{
  
    private int mAnimDuration = 400;
    private int mStrokeSize = 4;
    private int mWidth = 64;
    private int mHeight = 64;
    private int mRadius = 18;
    private int mInnerRadius = 10;
    private ColorStateList mStrokeColor;
    
    public Builder(){}
    
    public Builder(Context context, AttributeSet attrs, int defStyle){
      TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RadioButtonDrawable, 0, defStyle);
      
      width(a.getDimensionPixelSize(R.styleable.RadioButtonDrawable_rbd_width, ThemeUtil.dpToPx(context, 32)));
      height(a.getDimensionPixelSize(R.styleable.RadioButtonDrawable_rbd_height, ThemeUtil.dpToPx(context, 32)));
      strokeSize(a.getDimensionPixelSize(R.styleable.RadioButtonDrawable_rbd_strokeSize, ThemeUtil.dpToPx(context, 2)));
      radius(a.getDimensionPixelSize(R.styleable.RadioButtonDrawable_rbd_radius, ThemeUtil.dpToPx(context, 10)));
      innerRadius(a.getDimensionPixelSize(R.styleable.RadioButtonDrawable_rbd_innerRadius, ThemeUtil.dpToPx(context, 5)));
      strokeColor(a.getColorStateList(R.styleable.RadioButtonDrawable_rbd_strokeColor));
      animDuration(a.getInt(R.styleable.RadioButtonDrawable_rbd_animDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime)));
      
      a.recycle();
      
      if(mStrokeColor == null){
        int[][] states = new int[][]{
            new int[]{-android.R.attr.state_checked},
            new int[]{android.R.attr.state_checked},
        };
        int[] colors = new int[]{
            ThemeUtil.colorControlNormal(context, 0xFF000000),
            ThemeUtil.colorControlActivated(context, 0xFF000000),
        };        
        strokeColor(new ColorStateList(states, colors));
      }  
    }
        
    public RadioButtonDrawable build(){
      if(mStrokeColor == null)
        mStrokeColor = ColorStateList.valueOf(0xFF000000);
      
      return new RadioButtonDrawable(mWidth, mHeight, mStrokeSize, mStrokeColor, mRadius, mInnerRadius, mAnimDuration);
    }
        
    public Builder width(int width){
      mWidth = width;
      return this;
    }
    
    public Builder height(int height){
      mHeight = height;
      return this;
    }
    
    public Builder strokeSize(int size){
      mStrokeSize = size;
      return this;
    }
    
    public Builder strokeColor(int color){
      mStrokeColor = ColorStateList.valueOf(color);
      return this;
    }
    
    public Builder strokeColor(ColorStateList color){
      mStrokeColor = color;
      return this;
    }
    
    public Builder radius(int radius){
      mRadius = radius;
      return this;
    }
    
    public Builder innerRadius(int radius){
      mInnerRadius = radius;
      return this;
    }
    
    public Builder animDuration(int duration){
      mAnimDuration = duration;
      return this;
    }
  }
}




Java Source Code List

com.rey.material.ApplicationTest.java
com.rey.material.demo.ButtonFragment.java
com.rey.material.demo.MainActivity.java
com.rey.material.demo.ProgressFragment.java
com.rey.material.demo.SnackbarFragment.java
com.rey.material.demo.SwitchesFragment.java
com.rey.material.demo.TextfieldFragment.java
com.rey.material.drawable.ArrowDrawable.java
com.rey.material.drawable.BlankDrawable.java
com.rey.material.drawable.CheckBoxDrawable.java
com.rey.material.drawable.CircularProgressDrawable.java
com.rey.material.drawable.DividerDrawable.java
com.rey.material.drawable.LineMorphingDrawable.java
com.rey.material.drawable.LinearProgressDrawable.java
com.rey.material.drawable.NavigationDrawerDrawable.java
com.rey.material.drawable.RadioButtonDrawable.java
com.rey.material.drawable.RevealDrawable.java
com.rey.material.drawable.RippleDrawable.java
com.rey.material.drawable.ToolbarRippleDrawable.java
com.rey.material.util.ColorUtil.java
com.rey.material.util.ThemeUtil.java
com.rey.material.util.ViewUtil.java
com.rey.material.view.Button.java
com.rey.material.view.CheckBox.java
com.rey.material.view.CheckedTextView.java
com.rey.material.view.CompoundButton.java
com.rey.material.view.EditText.java
com.rey.material.view.FloatingActionButton.java
com.rey.material.view.ListPopupWindow.java
com.rey.material.view.ListView.java
com.rey.material.view.PopupWindow.java
com.rey.material.view.ProgressView.java
com.rey.material.view.RadioButton.java
com.rey.material.view.RippleManager.java
com.rey.material.view.SnackBar.java
com.rey.material.view.Spinner.java
com.rey.material.view.Switch.java
com.rey.material.view.TabPageIndicator.java
com.rey.material.view.TextView.java