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

  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>
时间: 2024-11-05 23:04:38

自定义控件 --- 加载旋转图标的相关文章

ASP.NET自定义控件加载资源WebResource问题

最近项目用日期控件,想把My97的资源文件跟TextBox封装成一个DatePicker控件,其实很简单的意见事情,但是还是用了一天多的时间,主要的问题就是解决资源文件加载的问题.通过一天多的努力,得出下面的结论: 1.自定义控件中,一般只要加载JS文件,但是所有的资源文件都需要在AssemblyInfo.cs中注册.具体方式如下: 1.1.控件中注册JS文件代码: /// <summary> /// 注册JS /// </summary> /// <param name=&

AngularJS中如果ng-src 图片加载失败怎么办

我们知道AngularJS加载图片的方法是用加ng-src标签,例如: <img ng-src="{{currentUrl}}"/> 其中currentUrl为图片地址,如果图片正常能显示,那这么使用一点问题没有,但是,如果图片加载失败了(例如该图片已经不存在,从而出现404错误),在该放图片的地方就会出现一个难看的图片加载失败图标,如果想把这个图标换成你自定义的图片,可以如下这么做: HTML: <img ng-src="{{currentUrl}}&qu

Android4.4 Framework分析——Android默认Home应用Launcher3的加载过程分析

本文主要介绍Android4.4默认Home应用Launcher3的启动过程和Launcher3的数据加载过程.Launcher的启动是开机时,ActivityManagerService准备好后开始的,下图是它的启动序列图: step1,SystemServer中,ActivityManagerService准备好了. step3, boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord targe

SDL2.0的加载图片贴图

加载图片贴图,采用了SDL_Window.SDL_Renderer.SDL_Texture和SDL_Image库 实例: 1 #include <stdio.h> 2 #include <math.h> 3 #include <string.h> 4 #include <SDL2\SDL.h> 5 #include <SDL2\SDL_image.h> 6 #include <SDL2\ex\SDL_rectex.h> 7 8 SDL

网络请求库和图片加载库

网络请求库 概述:所有网络库的原理是: 网络请求一般是基于HttpURLConnection和HttpClient进行封装的,也有自己编写Socket实现的,比如ion和OkHttp:请求的执行一般是通过线程池来管理,异步请求得到结果,则通过回调接口接收:并且一般接收结果的回调都通过Handler去在主线程执行 Ion的使用 详情查看Github主页https://github.com/koush/ion 介绍: 它支持网络请求和进行图片加载的双重功能 拥有链式api风格(Fluent API)

WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现

一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要有三种实现方式: 简单忙碌状态控件BusyBox: Win8/win10效果忙碌状态控件ProgressRing: 弹出异步等待框WaitingBox: 二.简单忙碌状态控件BusyBox 效果图: 通过属性"IsActive"控制控件是否启用,后台C#代码: /// <summary> /

【转】ionicLoading,ionic-spinner SVG旋转加载

原文链接:http://www.cnblogs.com/xuan-0... ionic 加载动作 $ionicLoading$ionicLoading 是 ionic 默认的一个加载交互效果.里面的内容也是可以在模板里面修改. angular.module('LoadingApp', ['ionic']) .controller('LoadingCtrl', function($scope, $ionicLoading) { $scope.show = function() { $ionicLo

CSS 实现加载动画之五-光盘旋转

原文:CSS 实现加载动画之五-光盘旋转 今天做的这个动画叫光盘旋转,名字自己取的.动画的效果估计很多人都很熟悉,就是微信朋友圈里的加载动画.做过前面几个动画,发现其实都一个原理,就是如何将动画的元素如何分离出来.这个动画的实现也很简单,关键点在于如何将元素拼凑成风车形状.然后定义动画的关键帧为rotate 360度,应用于整个元素上,就可以使整个元素旋转起来.案例在请在chrome中查看. 1. 先看截图 2. 代码实现思路 2.1 首先还是定义四个元素,元素的中心为这四个元素组成的圆的圆心.

CSS 实现加载动画之四-圆点旋转

原文:CSS 实现加载动画之四-圆点旋转 圆点旋转也是加载动画中经常用到的.其实现方式和菊花旋转一样,只不过一个是线条形式,一个是圆点形式.圆点按照固定的旋转角度排列,加上延时的改变透明度的动画就可以实现.这个实现也比较简单. 1. 动画截图 2. 案例源代码 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" Content="text/html