• 自定义控件 --- 加载旋转图标


          

      1 import android.annotation.TargetApi;
      2 import android.content.Context;
      3 import android.content.res.Resources;
      4 import android.content.res.TypedArray;
      5 import android.graphics.Canvas;
      6 import android.graphics.Paint;
      7 import android.graphics.RectF;
      8 import android.os.Build;
      9 import android.util.AttributeSet;
     10 import android.view.View;
     11 
     12 /**
     13  * 类似螺纹的加载view
     14  * 可以自定义的属性:颜色、旋转速度(X弧度/s)
     15  */
     16 public class WhorlView extends View {
     17     private static final int CIRCLE_NUM = 3;
     18 
     19     public static final int FAST = 1;
     20     public static final int MEDIUM = 0;
     21     public static final int SLOW = 2;
     22 
     23     private static final int PARALLAX_FAST = 60;
     24     private static final int PARALLAX_MEDIUM = 72;
     25     private static final int PARALLAX_SLOW = 90;
     26 
     27     private static final float SWEEP_ANGLE = 90f;
     28     private static final float STOKE_WIDTH = 5f;
     29     private static final long REFRESH_DURATION = 16L;
     30 
     31     private long mCircleTime;
     32     private int[] mLayerColors = new int[CIRCLE_NUM];
     33     private int mCircleSpeed;
     34     private int mParallaxSpeed;
     35 
     36     public WhorlView(Context context) {
     37         this(context, null, 0);
     38     }
     39 
     40     public WhorlView(Context context, AttributeSet attrs) {
     41         this(context, attrs, 0);
     42     }
     43 
     44     public WhorlView(Context context, AttributeSet attrs, int defStyleAttr) {
     45         super(context, attrs, defStyleAttr);
     46         Resources res = getResources();
     47         final int defaultSmallColor = res.getColor(R.color.material_red);
     48         final int defaultMiddleColor = res.getColor(R.color.material_green);
     49         final int defaultBigColor = res.getColor(R.color.material_blue);
     50         //默认外层最慢180度/s
     51         final int defaultCircleSpeed = 270;
     52         if (attrs != null) {
     53             final TypedArray typedArray = context.obtainStyledAttributes(
     54                     attrs, R.styleable.WhorlView_Style);
     55          mLayerColors[0] = typedArray.getColor(R.styleable.WhorlView_Style_WhorlView_SmallWhorlColor, defaultSmallColor);
     56             mLayerColors[1] = typedArray.getColor(R.styleable.WhorlView_Style_WhorlView_MiddleWhorlColor, defaultMiddleColor);
     57             mLayerColors[2] = typedArray.getColor(R.styleable.WhorlView_Style_WhorlView_BigWhorlColor, defaultBigColor);
     58             mCircleSpeed = typedArray.getInt(R.styleable.WhorlView_Style_WhorlView_CircleSpeed, defaultCircleSpeed);
     59             int index = typedArray.getInt(R.styleable.WhorlView_Style_WhorlView_Parallax, 0);
     60             setParallax(index);
     61             typedArray.recycle();
     62         } else {
     63             mLayerColors[0] = defaultSmallColor;
     64             mLayerColors[1] = defaultMiddleColor;
     65             mLayerColors[2] = defaultBigColor;
     66             mCircleSpeed = defaultCircleSpeed;
     67             mParallaxSpeed = PARALLAX_MEDIUM;
     68         }
     69     }
     70 
     72     private void setParallax(int index) {
     73         switch (index) {
     74             case FAST:
     75                 mParallaxSpeed = PARALLAX_FAST;
     76                 break;
     77             case MEDIUM:
     78                 mParallaxSpeed = PARALLAX_MEDIUM;
     79                 break;
     80             case SLOW:
     81                 mParallaxSpeed = PARALLAX_SLOW;
     82                 break;
     83             default:
     84                 throw new IllegalStateException("no such parallax type");
     85         }
     86     }
     87 
     88     @Override
     89     protected void onDraw(Canvas canvas) {
     90         super.onDraw(canvas);
     91         for (int i = 0; i < CIRCLE_NUM; i++) {
     92             float angle = (mCircleSpeed + mParallaxSpeed * (CIRCLE_NUM - i - 1)) * mCircleTime * 0.001f;
     93             drawArc(canvas, i, angle);
     94         }
     95     }
     96 
     97     private boolean mIsCircling = false;
     98 
     99     /**
    100      * 旋转开始 <功能简述>
    101      */
    102     public void start() {
    103         mIsCircling = true;
    104         new Thread(new Runnable() {
    105 
    106             @Override
    107             public void run() {
    108                 mCircleTime = 0L;
    109                 while (mIsCircling) {
    110                     invalidateWrap();
    111                     mCircleTime = mCircleTime + REFRESH_DURATION;
    112                     try {
    113                         Thread.sleep(REFRESH_DURATION);
    114                     } catch (InterruptedException e) {
    115                         e.printStackTrace();
    116                     }
    117                 }
    118             }
    119         }).start();
    120     }
    121 
    122     public void stop() {
    123         mIsCircling = false;
    124         mCircleTime = 0L;
    125         invalidateWrap();
    126     }
    127 
    128     public boolean isCircling(){
    129         return mIsCircling;
    130     }
    131 
    132     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    133     private void invalidateWrap() {
    134         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    135             postInvalidateOnAnimation();
    136         } else {
    137             postInvalidate();
    138         }
    139     }
    140 
    141     /**
    142      * 画弧
    143      *
    144      * @param canvas
    145      * @param index      由内而外
    146      * @param startAngle
    147      */
    148     private void drawArc(Canvas canvas, int index, float startAngle) {
    149         Paint paint = checkArcPaint(index);
    150         //最大圆是view的边界
    151         RectF oval = checkRectF(calcuRadiusRatio(index));
    152         canvas.drawArc(oval, startAngle, SWEEP_ANGLE, false, paint);
    153     }
    154 
    155     private Paint mArcPaint;
    156 
    157     private Paint checkArcPaint(int index) {
    158         if (mArcPaint == null) {
    159             mArcPaint = new Paint();
    160         } else {
    161             mArcPaint.reset();
    162         }
    163         mArcPaint.setColor(mLayerColors[index]);
    164         mArcPaint.setStyle(Paint.Style.STROKE);
    165         mArcPaint.setStrokeWidth(STOKE_WIDTH);
    166         mArcPaint.setAntiAlias(true);
    167         return mArcPaint;
    168     }
    169 
    170     private RectF mOval;
    171 
    172     private RectF checkRectF(float radiusRatio) {
    173         if (mOval == null) {
    174             mOval = new RectF();
    175         }
    176         float start = getMinLength() * 0.5f * (1 - radiusRatio) + STOKE_WIDTH;
    177         float end = getMinLength() - start;
    178         mOval.set(start, start, end, end);
    179         return mOval;
    180     }
    181 
    182     private static final float RADIUS_RATIO_P = 0.2f;
    183 
    184     /**
    185      * 计算每一圈的半径比例
    186      *
    187      * @param index
    188      * @return
    189      */
    190     private float calcuRadiusRatio(int index) {
    191         return 1f - (CIRCLE_NUM - index - 1) * RADIUS_RATIO_P;
    192     }
    193 
    194     private int getMinLength() {
    195         return Math.min(getWidth(), getHeight());
    196     }
    197 
    198     @Override
    199     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    200         int minSize = (int) (STOKE_WIDTH * 4 * CIRCLE_NUM);
    201         int wantSize = (int) (STOKE_WIDTH * 8 * CIRCLE_NUM);
    202         int size = measureSize(widthMeasureSpec, wantSize, minSize);
    203         setMeasuredDimension(size, size);
    204     }
    205 
    206     /**
    207      * 测量view的宽高
    208      *
    209      * @param measureSpec
    210      * @param wantSize
    211      * @param minSize
    212      * @return
    213      */
    214     public static int measureSize(int measureSpec, int wantSize, int minSize) {
    215         int result = 0;
    216         int specMode = MeasureSpec.getMode(measureSpec);
    217         int specSize = MeasureSpec.getSize(measureSpec);
    218 
    219         if (specMode == MeasureSpec.EXACTLY) {
    220             // 父布局想要view的大小
    221             result = specSize;
    222         } else {
    223             result = wantSize;
    224             if (specMode == MeasureSpec.AT_MOST) {
    225                 // wrap_content
    226                 result = Math.min(result, specSize);
    227             }
    228         }
    229         //测量的尺寸和最小尺寸取大
    230         return Math.max(result, minSize);
    231     }
    232 }

    values/attrs.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <resources>
     3     <declare-styleable name="WhorlView_Style">
     4         <attr name="WhorlView_SmallWhorlColor" format="color" />
     5         <attr name="WhorlView_MiddleWhorlColor" format="color" />
     6         <attr name="WhorlView_BigWhorlColor" format="color" />
     7         <attr name="WhorlView_CircleSpeed" format="integer" />
     8         <attr name="WhorlView_Parallax">
     9             <enum name="fast" value="1" />
    10             <enum name="medium" value="0" />
    11             <enum name="slow" value="2" />
    12         </attr>
    13     </declare-styleable>
    14 </resources>

    以上是自定义控件代码和资源文件。下面是如何使用自定义控件。

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="50dp" >
        <com.dr.WhorlView
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/whorl"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            app:WhorlView_CircleSpeed="270"
            app:WhorlView_Parallax="fast"
            app:WhorlView_MiddleWhorlColor="@color/material_red"
            app:WhorlView_SmallWhorlColor="@color/material_green" /> 
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/whorl"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="18dp"
            android:text="加载中..."
            android:textAppearance="?android:attr/textAppearanceMedium" />
    </RelativeLayout>
     1 public class MainActivity extends Activity {
     2     @Override
     3     protected void onCreate(Bundle savedInstanceState) {
     4         super.onCreate(savedInstanceState);
     5         setContentView(R.layout.activity_main);
     6         final WhorlView whorlView = (WhorlView) this.findViewById(R.id.whorl);
     8         whorlView.setOnClickListener(new View.OnClickListener() {
     9             @Override
    10             public void onClick(View v) {
    11                 if (whorlView.isCircling()) {
    12                     whorlView.stop();
    13                 } else {
    14                     whorlView.start();
    15                 }
    16             }
    17         });
    18     }
    19 }

    values/color.xml

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <resources>
    3     <color name="material_red">#F44336</color>
    4     <color name="material_green">#4CAF50</color>
    5     <color name="material_blue">#5677fc</color>
    6 </resources>
  • 相关阅读:
    高质量的函数 —— 《clean code》读后感
    保证代码的高质量 —— 《clean code》读后感
    [转 TDD] 如何坚持TDD:使用者出现的问题以及解决方案
    注释 —— 《clean code》读后感
    注释 —— 《clean code》读后感
    如何命名 —— 《clean code》读后感
    高质量的函数 —— 《clean code》读后感
    保证代码的高质量 —— 《clean code》读后感
    格式 —— 《clean code》读后感
    华为内部面试题库(14)
  • 原文地址:https://www.cnblogs.com/androidsj/p/4798579.html
Copyright © 2020-2023  润新知