今天貌似生病了……直接来代码
自定义View代码
package com.lizw.circular.wave; import com.lizw.circular.R; import com.lizw.circular.R.attr; import com.lizw.circular.R.drawable; import com.lizw.circular.R.styleable; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.View; /** * * @author Troy Lee * */ public class CircularView extends View { //背景圆所在的区域 private final RectF mCircleBounds = new RectF(); // //thumb所在举行 // private final RectF mSquareRect = new RectF(); //底层大圆的画笔 private Paint mBackgroundColorPaint = null; //底层大圆边宽 private int mCircleStrokeWidth = 10; private int mGravity = Gravity.CENTER; //Horizontal的内边界技术依赖于mGravity private int mHorizontalInset = 0; //Vertical的内边界技术依赖于mGravity private int mVerticalInset = 0; //所有属性设置完成为true,此时在Layout View时候将不会发生错误 private boolean mIsInitializing = true; //thumb是否可见 private boolean mIsThumbEnabled = true; //thumb沿着底层圆转的进度 private float mProgress = 0.0f; //thumb沿着底层圆转前的路径颜色 private int mProgressBackgroundColor; //thumb沿着底层圆转后留下的路径颜色 private int mProgressColor; //thumb沿着底层圆转所用的画笔 private Paint mProgressColorPaint; //底层大圆的半径 private float mRadius; //thumb的画笔 private Paint mThumbColorPaint = null; //thumb的坐标 x private float mThumbPosX; //thumb的坐 y private float mThumbPosY; //thumb的半径 private int mThumbRadius = 20; //我们用自己坐标系统的变化偏移量X private float mTranslationOffsetX; //我们用自己坐标系统的变化偏移量Y private float mTranslationOffsetY; /** * Instantiates a new holo circular progress bar. * * @param context the context */ public CircularView(final Context context) { this(context, null); } /** * Instantiates a new holo circular progress bar. * * @param context the context * @param attrs the attrs */ public CircularView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.circularProgressBarStyle); } /** * Instantiates a new holo circular progress bar. * * @param context the context * @param attrs the attrs * @param defStyle the def style */ public CircularView(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); // load the styled attributes and set their properties final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularView,defStyle, 0); if (attributes != null) { try { setProgressColor(attributes.getColor(R.styleable.CircularView_progress_color, Color.CYAN)); setProgressBackgroundColor(attributes.getColor(R.styleable.CircularView_progress_background_color,Color.GREEN)); setProgress(attributes.getFloat(R.styleable.CircularView_progress, 0.0f)); setWheelSize((int) attributes.getDimension(R.styleable.CircularView_stroke_width, 10)); setThumbEnabled(attributes.getBoolean(R.styleable.CircularView_thumb_visible, true)); mGravity = attributes.getInt(R.styleable.CircularView_android_gravity,Gravity.CENTER); } finally { // make sure recycle is always called. attributes.recycle(); } } mThumbRadius = mCircleStrokeWidth * 2; mBackgroundColorPaint = new Paint(); mThumbColorPaint = new Paint(); updateBackgroundColor(); updateProgressColor(); // the view has now all properties and can be drawn mIsInitializing = false; } private Bitmap ballBitmap; @Override protected void onDraw(final Canvas canvas) { // All of our positions are using our internal coordinate system. // Instead of translating // them we let Canvas do the work for us. canvas.translate(mTranslationOffsetX, mTranslationOffsetY); final float progressRotation = getCurrentRotation(); // // draw the background canvas.drawArc(mCircleBounds, 270, 360, false,mBackgroundColorPaint); if (isThumbEnabled()) { // 根据进度画thumb图标转的路径 canvas.drawArc(mCircleBounds, 270, progressRotation, false,mProgressColorPaint); //save()作用:在save()方法之前的全都保存,在save()方法之后,restore()方法之前的都清空。 canvas.save(); // 将thumb图标初始位置放到0度 canvas.rotate(progressRotation - 90); // // 将小方形图标正向旋转45度 // canvas.rotate(45, mThumbPosX, mThumbPosY); // mSquareRect.left = mThumbPosX - mThumbRadius / 3; // mSquareRect.right = mThumbPosX + mThumbRadius / 3; // mSquareRect.top = mThumbPosY - mThumbRadius / 3; // mSquareRect.bottom = mThumbPosY + mThumbRadius / 3; // canvas.drawRect(mSquareRect, mThumbColorPaint); //设置thumb图标为小球 ballBitmap = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_detectiontrack)); canvas.drawBitmap(ballBitmap, mThumbPosX-ballBitmap.getWidth()/2f, mThumbPosY - ballBitmap.getHeight()/2f, mThumbColorPaint); canvas.restore(); } } @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final int height = getDefaultSize(getSuggestedMinimumHeight() + getPaddingTop() + getPaddingBottom() ,heightMeasureSpec); final int width = getDefaultSize(getSuggestedMinimumWidth() + getPaddingLeft() + getPaddingRight(), widthMeasureSpec); //所要画出圆形的目标直径 final int diameter; if (heightMeasureSpec == MeasureSpec.UNSPECIFIED) { // ScrollView diameter = width; computeInsets(0, 0); } else if (widthMeasureSpec == MeasureSpec.UNSPECIFIED) { // HorizontalScrollView diameter = height; computeInsets(0, 0); } else { // Default diameter = Math.min(width, height); computeInsets(width - diameter, height - diameter); } setMeasuredDimension(diameter, diameter); final float halfDiameter = diameter * 0.5f; // 所画圆形的边宽 final float drawedWith; if (isThumbEnabled()) { drawedWith = mThumbRadius * (5f / 6f); } else { drawedWith = mCircleStrokeWidth / 2f; } // 所要画圆形的半径;-10.5f 是为了更好的融入到RectF中,起到padding的作用 mRadius = halfDiameter - drawedWith - 10.5f; mCircleBounds.set(-mRadius, -mRadius, mRadius, mRadius); mThumbPosX = (float) (mRadius * Math.cos(0)); mThumbPosY = (float) (mRadius * Math.sin(0)); mTranslationOffsetX = halfDiameter + mHorizontalInset; mTranslationOffsetY = halfDiameter + mVerticalInset; } public int getCircleStrokeWidth() { return mCircleStrokeWidth; } /** * gives the current progress of the ProgressBar. Value between 0..1 if you set the progress to * >1 you'll get progress % 1 as return value * * @return the progress */ public float getProgress() { return mProgress; } /** * Gets the progress color. * * @return the progress color */ public int getProgressColor() { return mProgressColor; } /** * @return true if the marker is visible */ public boolean isThumbEnabled() { return mIsThumbEnabled; } /** * Sets the progress. * * @param progress * the new progress */ public void setProgress(final float progress) { if (progress >= 1.0f) { mProgress = 1.0f; } else { mProgress = progress % 1.0f; } // Log.e("", "progress is : " + progress + " ,mProgress is : " + mProgress); if (!mIsInitializing) { invalidate(); } } /** * Sets the progress background color. * * @param color the new progress background color */ public void setProgressBackgroundColor(final int color) { mProgressBackgroundColor = color; updateBackgroundColor(); } /** * Sets the progress color. * * @param color the new progress color */ public void setProgressColor(final int color) { mProgressColor = color; updateProgressColor(); } /** * shows or hides the thumb of the progress bar * * @param enabled true to show the thumb */ public void setThumbEnabled(final boolean enabled) { mIsThumbEnabled = enabled; } /** * Sets the wheel size. * * @param dimension the new wheel size */ public void setWheelSize(final int dimension) { mCircleStrokeWidth = dimension; // update the paints updateBackgroundColor(); updateProgressColor(); } /** * Compute insets. * * <pre> * ______________________ * |_________dx/2_________| * |......| /'''''\|......| * |-dx/2-|| View ||-dx/2-| * |______| \_____/|______| * |________ dx/2_________| * </pre> * * @param dx the dx the horizontal unfilled space * @param dy the dy the horizontal unfilled space */ @SuppressLint("NewApi") private void computeInsets(final int dx, final int dy) { int absoluteGravity = mGravity; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { absoluteGravity = Gravity.getAbsoluteGravity(mGravity, getLayoutDirection()); } switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: mHorizontalInset = 0; break; case Gravity.RIGHT: mHorizontalInset = dx; break; case Gravity.CENTER_HORIZONTAL: default: mHorizontalInset = dx / 2; break; } switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) { case Gravity.TOP: mVerticalInset = 0; break; case Gravity.BOTTOM: mVerticalInset = dy; break; case Gravity.CENTER_VERTICAL: default: mVerticalInset = dy / 2; break; } } /** * Gets the current rotation. * * @return the current rotation */ private float getCurrentRotation() { return 360f * mProgress; } /** * updates the paint of the background */ private void updateBackgroundColor() { mBackgroundColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBackgroundColorPaint.setColor(mProgressBackgroundColor); mBackgroundColorPaint.setStyle(Paint.Style.STROKE); mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth); invalidate(); } /** * updates the paint of the progress and the thumb to give them a new visual style */ private void updateProgressColor() { mProgressColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mProgressColorPaint.setColor(mProgressColor); mProgressColorPaint.setStyle(Paint.Style.STROKE); mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth); mThumbColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mThumbColorPaint.setColor(mProgressColor); mThumbColorPaint.setStyle(Paint.Style.FILL_AND_STROKE); mThumbColorPaint.setStrokeWidth(mCircleStrokeWidth); invalidate(); } }
Activity代码
package com.lizw.circular; import com.lizw.circular.wave.CircularView; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; /** * Troy Lee */ public class CircularActivity extends Activity { private static final String TAG = CircularActivity.class.getSimpleName(); /** * The Switch button. */ private CircularView circularView; private ObjectAnimator objAnimator; /* * (non-Javadoc) * * @see android.app.Activity#onCreate(android.os.Bundle) */ @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); circularView = (CircularView) findViewById(R.id.circularView); } public void startAnimate(View view) { animate(circularView,new AnimatorListener() { @Override public void onAnimationCancel(final Animator animation) { circularView.setProgress(0.0f); } @Override public void onAnimationEnd(final Animator animation) { circularView.setProgress(1.0f); } @Override public void onAnimationRepeat(final Animator animation) { } @Override public void onAnimationStart(final Animator animation) { circularView.setProgress(0.0f); } }); // new Handler().postDelayed(new Runnable() { // // @Override // public void run() { // // TODO Auto-generated method stub // if(objAnimator != null){ // objAnimator.cancel(); // // circularView.setProgress(0.0f); // } // } // }, 3000); } /** * Animate. * * @param progressBar the progress bar * @param listener the listener */ private void animate(final CircularView circularView,final AnimatorListener listener) { final float progress = 1.00f; int duration = 5000; circularView.setProgress(0.0f); animate(circularView, listener, progress, duration); } private void animate(final CircularView circularView, final AnimatorListener listener,final float progress, final int duration) { objAnimator = ObjectAnimator.ofFloat(circularView, "progress", progress); objAnimator.setDuration(duration); objAnimator.addListener(new AnimatorListener() { @Override public void onAnimationCancel(final Animator animation) { circularView.setProgress(0.0f); } @Override public void onAnimationEnd(final Animator animation) { circularView.setProgress(1.0f); } @Override public void onAnimationRepeat(final Animator animation) { } @Override public void onAnimationStart(final Animator animation) { circularView.setProgress(0.0f); } }); if (listener != null) { objAnimator.addListener(listener); } objAnimator.addUpdateListener(new AnimatorUpdateListener() { float count = 0.0f; @Override public void onAnimationUpdate(final ValueAnimator animation) { count=0.01f; circularView.setProgress(count); } }); // circularView.setMarkerProgress(progress); objAnimator.start(); } }
attr.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircularView"> <attr name="stroke_width" format="dimension" /> <attr name="progress" format="float" /> <attr name="progress_color" format="color" /> <attr name="progress_background_color" format="color" /> <attr name="thumb_visible" format="boolean" /> <attr name="android:gravity" /> </declare-styleable> <attr name="circularStyle" format="reference" /> </resources>
styles.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="Circular"> <item name="android:layout_height">wrap_content</item> <item name="android:layout_width">match_parent</item> <item name="stroke_width">5dp</item> <item name="progress" format="float">0</item> <item name="progress_color">#46A4EC</item> <item name="progress_background_color">#adff2f</item> <item name="thumb_visible">true</item> </style> <style name="CircularLight"> <item name="android:layout_height">wrap_content</item> <item name="android:layout_width">match_parent</item> <item name="stroke_width">5dp</item> <item name="progress" format="float">0</item> <item name="progress_color">#46A4EC</item> <item name="progress_background_color">#adff2f</item> <item name="thumb_visible">true</item> </style> </resources>
themes.xml
<resources> <!-- Application theme. --> <style name="AppTheme" parent="android:Theme.Holo"> <item name="circularStyle">@style/Circular</item> </style> <style name="AppThemeLight" parent="android:Theme.Holo.Light"> <item name="circularStyle">@style/CircularLight</item> </style> </resources>
activity_home.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/com.lizw.circular" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" > <com.lizw.circular.wave.CircularView android:id="@+id/circularView" android:layout_marginTop="20dp" android:layout_width="match_parent" android:layout_height="300dp" app:progress="0" /> <Button android:layout_marginTop="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="startAnimate" android:text="试试动画"/> </LinearLayout>
运行效果
相关推荐
环形动画进度数字时钟是一种视觉效果独特的时间显示方式,它将传统的数字时钟与动态的环形进度条相结合,创造出既美观又直观的时钟界面。这种设计常见于现代的用户界面(UI)和应用设计中,尤其适用于增强用户交互...
环形动画菜单特效是一种利用CSS3技术实现的创新交互设计,它为网站的导航菜单带来了独特的视觉体验。这种菜单在静止状态下呈现环形布局,当用户点击中心按钮时,子菜单会按照特定的动画效果从中心向外展开,提供丰富...
C#,环形,动画,进度控件,C#的环形动画进度控件 C#,环形,动画,进度控件,C#的环形动画进度控件 C#,环形,动画,进度控件,C#的环形动画进度控件 C#,环形,动画,进度控件,C#的环形动画进度控件 C#,环形,动画,进度控件,C#的...
本案例"CSS3二级环形动画菜单.zip"正是利用这些特性来创建一个独特且吸引人的交互式菜单。 首先,我们要理解"二级环形动画菜单"的概念。这通常指的是一个主菜单项周围分布着子菜单项,当用户悬停在主菜单项上时,子...
今天我们要分享一款非常有创意的HTML5/CSS3动画菜单,菜单是环形的,当鼠标点击中心按钮时,子菜单即会环绕展开,并伴随很酷的菜单展开动画。记得之前还分享过一款HTML5/CSS3实现iOS Path菜单,也是环形的菜单,动画...
"H5 CSS3环形动画"这个主题,就是关于如何利用这两种技术来创建引人注目的环形动画效果。这篇博客文章可能是探讨如何通过CSS3的动画属性和HTML5的结构元素,来实现这种视觉上的创新。 首先,我们来了解一下HTML5。...
环形动画导航菜单jQuery插件是一款用于网页交互设计的工具,它通过JavaScript库jQuery实现,为网站的导航菜单带来独特的视觉效果。这款插件利用HTML、CSS和JavaScript技术,将传统线性的导航菜单转变为环形布局,...
环形动画效果导航菜单是一种独特且引人注目的网页交互设计,它利用jQuery和CSS技术为用户提供了非线性的导航体验。这种设计通常用于展示多个主要功能或分类,以一个中心点为轴心,菜单项以环形排列,通过动态的过渡...
在“html5 canvas 3D方块环形动画特效”这个项目中,我们主要探讨的是如何利用Canvas API创建一个立体的3D方块环形动画,其中每个方块的六个面颜色各异,并且可以通过鼠标交互来实现全方位的旋转控制。 首先,要...
"仿招行信用卡已出账单环形动画效果"是一种创新的UI设计,它能够以动态且直观的方式展示用户的信用卡账单状态。这种动画效果通常应用于移动应用或者网页中,让用户能够一目了然地了解自己的消费情况。 环形动画的...
在CSS世界中,创建动态和引人入胜的视觉效果是一项常见的挑战,而环形动画则是其中一种吸引眼球的设计元素。本教程将详细介绍如何仅使用CSS来实现这种效果,无需JavaScript的介入,使得动画在移动端和PC端都有良好的...
在iOS开发中,实现“垂直循环滚动,环形动画进度条”的功能,通常涉及到自定义UI组件和动画处理。这个功能结合了两个重要的视觉元素:一个垂直方向的跑马灯效果,以及一个环形动画进度条。下面我们将深入探讨这两个...
"CSS3超酷环形动画菜单"就是一个很好的例子,它利用了CSS3的高级特性,如选择器、转换(transform)、过渡(transition)和动画(animation),来实现一个独特且引人注目的菜单导航。 首先,CSS3的选择器使得我们...
在这个“Canvas 3D方块环形动画特效”中,用户可以看到环形排列的3D方块在网页上进行流畅的旋转,这种动态效果极大地提升了网页的视觉冲击力和互动性。 文件名"jiaoben6902"可能是源代码或资源文件的名称,通常在...
"Flash环形动画"是一个特定的领域,它涉及到使用Adobe Flash软件来创建动态的环状图形,这种图形常用于表示进度条加载效果。下面将详细阐述Flash环形动画的制作过程、相关技术以及其在实际应用中的价值。 首先,...
本项目名为"经典载入环形动画进度控件的C#源码",主要关注的是在C#环境下,使用Visual Studio 2005开发的一款动画进度指示器。 进度控件是用户界面中的常见元素,用于向用户展示操作的进度或等待状态。在这个项目中...
在“CSS3超酷环形动画菜单其子菜单可环绕展开”这个主题中,我们主要关注的是如何利用CSS3来创建一种创新且引人注目的交互式菜单设计。 首先,环形布局在UI设计中并不常见,但它可以为网站带来独特的视觉效果。要...