先上图看一下闹钟唤期页面的效果

实现的功能:

1:转动的图片根据天气情况更换

2:转动时间可以设置,转动结束,闹铃声音就结束

3:光圈颜色渐变效果

直接上代码啦:

package com.example.sirius.extension.customview;import android.animation.Animator;
import android.animation.ValueAnimator;
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.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;import com.yuekong.sirius.extension.R;
import com.yuekong.sirius.extension.util.ExtendUtil;import java.text.SimpleDateFormat;/*** Created by Zhongqi.Shao on 2016/12/5.*/
public class ClockWakeView extends View {//最外一层圆的颜色private int mOutCircleColor;//最外一层圆的半径private int mOutCircleRadis;//内圆的颜色private int mInnerCircleColor;//内圆的半径private int mInnerCircleRadis;private int mWidth;private int mHeight;//默认宽度private final int DEFAULT_WIDTH = dp2px(240);//默认高度private final int DEFAULT_HEIGHT = dp2px(240);//最外圆的默认半径private int DEFAULT_OUT_RADIS = dp2px(120);//内圆的默认半径private int DeFAULT_INNER_RADIS = dp2px(105);//标题距离顶部的默认距离private int DEFAULT_TITLE_PADDING_TOP = dp2px(40);//最外层圆形的Paintprivate Paint mOutCirclePaint;//内圆的Paintprivate Paint mInnerCirclePaint;//标题Paintprivate Paint mTitlePaint;//渐变弧private Paint mGradientArcPaint;private SweepGradient mSweepGradient;//日期时间Paintprivate Paint mTimePaint;private Paint mDatePaint;//时间分隔的图片private Bitmap mDividerPic;//天气图片private Bitmap mWeatherPic;//标题private String mTitle;//当前时间private long mCurrentDate = 1481010829605L;private SimpleDateFormat mFormat;private Ringtone mRingTone;//图片在倒计时几分钟内走完一个周期 根据音乐时间来计算private long mCountDownTime;//倒计时转过的角度private float mCurrentAngle;//倒计时结束回调private CountdownFinishListener mCountdownListener;private Context mContext;public ClockWakeView(Context context) {this(context, null);mContext = context;}public ClockWakeView(Context context, AttributeSet attrs) {this(context, attrs, 0);mContext = context;}public ClockWakeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SiriusClockWakeView);mOutCircleColor = ta.getColor(R.styleable.SiriusClockWakeView_outColor, context.getResources().getColor(R.color.out_circle_color));mOutCircleRadis = (int) ta.getDimension(R.styleable.SiriusClockWakeView_outCircleRadis, DEFAULT_OUT_RADIS);mInnerCircleColor = context.getResources().getColor(R.color.inner_circle_color);mInnerCircleRadis = DeFAULT_INNER_RADIS;mTitle = context.getResources().getString(R.string.clock);ta.recycle();initPaint();}private void initPaint() {mFormat = new SimpleDateFormat("MM月dd日_HH_mm_EEEE");//获取分隔图片mDividerPic = BitmapFactory.decodeResource(getResources(), R.drawable.time_divider);mWeatherPic = BitmapFactory.decodeResource(getResources(), R.drawable.icon_weather);//外圆的paintmOutCirclePaint = new Paint();mOutCirclePaint.setAntiAlias(true);mOutCirclePaint.setStyle(Paint.Style.STROKE);mOutCirclePaint.setStrokeWidth(dp2px(5));mOutCirclePaint.setColor(mOutCircleColor);//内圆的PaintmInnerCirclePaint = new Paint();mInnerCirclePaint.setAntiAlias(true);mInnerCirclePaint.setStyle(Paint.Style.STROKE);mInnerCirclePaint.setStrokeWidth(dp2px(5));mInnerCirclePaint.setColor(mInnerCircleColor);//标题的PaintmTitlePaint = new Paint();mTitlePaint.setAntiAlias(true);mTitlePaint.setStyle(Paint.Style.FILL);mTitlePaint.setColor(mContext.getResources().getColor(R.color.nav_highlighted));mTitlePaint.setTextSize(sp2px(14));//时间的PaintmTimePaint = new Paint();mTimePaint.setAntiAlias(true);mTimePaint.setColor(Color.WHITE);mTimePaint.setStyle(Paint.Style.FILL);mTimePaint.setTextSize(sp2px(70));//日期的PaintmDatePaint = new Paint();mDatePaint.setAntiAlias(true);mDatePaint.setColor(Color.WHITE);mDatePaint.setStyle(Paint.Style.FILL);mDatePaint.setTextSize(sp2px(14));//渐变弧的PaintmGradientArcPaint = new Paint();mGradientArcPaint.setAntiAlias(true);mGradientArcPaint.setStyle(Paint.Style.STROKE);mGradientArcPaint.setStrokeWidth(dp2px(5));mGradientArcPaint.setStrokeCap(Paint.Cap.BUTT);mGradientArcPaint.setStrokeJoin(Paint.Join.MITER);//设置渐变的颜色int[] colors = {0x00AEA1FF, 0x40AEA1FF, 0xFFAEA1FF, 0xFFAEA1FF};//渐变色mSweepGradient = new SweepGradient(0, 0, colors, null);mGradientArcPaint.setShader(mSweepGradient);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = startMeasure(widthMeasureSpec);mHeight = startMeasure(heightMeasureSpec);setMeasuredDimension(mWidth, mHeight);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//移动画布到中间canvas.translate(mWidth / 2, mHeight / 2);//绘制最外层的圆形drawOutCircle(canvas);//绘制内圆drawInnerCircle(canvas);//绘制中间的分隔图片drawDividerPic(canvas);//绘制标题drawTitle(canvas);//绘制时间drawDateTime(canvas);//绘制旋转图片drawLightArc(canvas);}private void drawOutCircle(Canvas canvas) {canvas.save();canvas.drawCircle(0, 0, mOutCircleRadis, mOutCirclePaint);canvas.restore();}private void drawInnerCircle(Canvas canvas) {canvas.save();canvas.drawCircle(0, 0, mInnerCircleRadis, mInnerCirclePaint);canvas.restore();}private void drawDividerPic(Canvas canvas) {canvas.save();canvas.drawBitmap(mDividerPic, null, new Rect(-dp2px(3), -dp2px(14), dp2px(3), dp2px(14)), null);canvas.restore();}private void drawTitle(Canvas canvas) {canvas.save();if (mTitle == null || mTitle.length() <= 0) {return;}float textWidth = mTitlePaint.measureText(mTitle);float baseLine = DeFAULT_INNER_RADIS - DEFAULT_TITLE_PADDING_TOP;canvas.drawText(mTitle, -textWidth / 2, -baseLine, mTitlePaint);canvas.restore();}private void drawLightArc(Canvas canvas) {canvas.save();canvas.rotate(mCurrentAngle);RectF rect = new RectF(-mInnerCircleRadis, -mInnerCircleRadis, mInnerCircleRadis, mInnerCircleRadis);canvas.drawArc(rect, -270, 180, false, mGradientArcPaint);canvas.drawBitmap(mWeatherPic, null, new Rect(-dp2px(12), -mInnerCircleRadis - dp2px(12), dp2px(12), dp2px(12) - mInnerCircleRadis), null);canvas.restore();}private void drawDateTime(Canvas canvas) {canvas.save();String timeStr = ExtendUtil.getAllFormatStr(mFormat, mCurrentDate);String[] array = timeStr.split("_");String date = array[0];String hour = array[1];String minute = array[2];String wake = array[3];float width = mTimePaint.measureText(hour);RectF targetRect = new RectF(-(width + dp2px(40)), -sp2px(70) / 2, -dp2px(40), sp2px(70) / 2);Paint.FontMetricsInt fontMetrics = mTimePaint.getFontMetricsInt();int baseline = (int) (targetRect.top + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top);canvas.drawText(hour, -width - dp2px(15), baseline, mTimePaint);float minuteWidth = mTimePaint.measureText(minute);RectF minuteRect = new RectF(dp2px(15), -sp2px(70) / 2, dp2px(15) + minuteWidth, sp2px(70) / 2);Paint.FontMetricsInt minuteMetrics = mTimePaint.getFontMetricsInt();int minuteLine = (int) (minuteRect.top + (minuteRect.bottom - minuteRect.top - minuteMetrics.bottom + minuteMetrics.top) / 2 - minuteMetrics.top);canvas.drawText(minute, dp2px(15), minuteLine, mTimePaint);String dateStr = date + "  " + wake;float dateWidth = mDatePaint.measureText(dateStr);RectF dateRect = new RectF(-dateWidth / 2, sp2px(30), dateWidth / 2, sp2px(30) + sp2px(14));Paint.FontMetricsInt dateMetrics = mTimePaint.getFontMetricsInt();int dateLine = (int) (dateRect.top + (dateRect.bottom - dateRect.top - dateMetrics.bottom + dateMetrics.top) / 2 - dateMetrics.top);canvas.drawText(dateStr, -dateWidth / 2, dateLine, mDatePaint);canvas.restore();}private int startMeasure(int whSpec) {int result = 0;int size = MeasureSpec.getSize(whSpec);int mode = MeasureSpec.getMode(whSpec);if (mode == MeasureSpec.EXACTLY) {result = size;} else {result = DEFAULT_WIDTH;}return result;}//开始倒计时计算闹钟结束public void startCountDown() {ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0f);animator.setDuration(mCountDownTime);//匀速animator.setInterpolator(new LinearInterpolator());//不循环animator.setRepeatCount(0);//监听动画过程中值得实时变化animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {mCurrentAngle = (float) valueAnimator.getAnimatedValue() * 360;invalidate();}});animator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {}@Overridepublic void onAnimationEnd(Animator animator) {if (mRingTone != null && mRingTone.isPlaying()) {mRingTone.stop();}if (mCountdownListener != null) {mCountdownListener.countdownFinished();}}@Overridepublic void onAnimationCancel(Animator animator) {}@Overridepublic void onAnimationRepeat(Animator animator) {}});animator.start();//播放闹钟铃声Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);mRingTone = RingtoneManager.getRingtone(mContext, notification);if (mRingTone != null && !mRingTone.isPlaying()) {mRingTone.play();}}//提供设置倒计时的方法public void setCountDownTime(long time, CountdownFinishListener listener) {mCountDownTime = time;mCountdownListener = listener;}//设置当前日期时间public void setCurrentTime(long currentTime) {mCurrentDate = currentTime;invalidate();}private int dp2px(int dp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());}private int sp2px(int sp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());}public interface CountdownFinishListener {//倒计时结束操作void countdownFinished();}}

Android自定义View 闹钟唤起播放闹钟铃声实现相关推荐

  1. Android5.0自定义闹钟,Android自定义View 实现闹钟唤起播放闹钟铃声功能

    先上图看一下闹钟唤期页面的效果 实现的功能: 1:转动的图片根据天气情况更换 2:转动时间可以设置,转动结束,闹铃声音就结束 3:光圈颜色渐变效果 直接上代码啦: package com.yuekon ...

  2. android 自定义音乐圆形进度条,Android自定义View实现音频播放圆形进度条

    本篇文章介绍自定义View配合属性动画来实现如下的效果 实现思路如下: 根据播放按钮的图片大小计算出圆形进度条的大小 根据音频的时间长度计算出圆形进度条绘制的弧度 通过Handler刷新界面来更新圆形 ...

  3. Android 自定义view 高仿小米闹钟

    效果图: 代码github地址:https://github.com/chenzongwen/MiClockView

  4. Android 自定义 View - 适用于音乐播放的“条形与波浪”可视化效果

    为媒体资源播放打造的"条形与波浪"可视化效果 1 截图 2 说明 1 提供的 xml 属性 barColor 横条颜色 barHeight 横条高度 waveRange 波浪条极差 ...

  5. Android自定义View实现喜马拉雅播放状态切换

    最近在喜马拉雅听书发现它的播放和暂停状态切换的动画挺有意思的. 在脑子里想了下如何实现, 画了画图, 就开始肝了. 最开始是用贝塞尔曲线去做点的位置的移动效果, 虽然做出来了, 但发现两个path的变 ...

  6. Android自定义View绘制闹钟

    Android自定义View绘制闹钟 本文简单实现了一个闹钟,扩展View,Canvas绘制 效果如下: 代码如下: package com.gaofeng.mobile.clock_demo;imp ...

  7. Android自定义view详解,使用实例,自定义属性,贝塞尔曲线

    //只会触发执行onDraw方法,只会改变绘制里面的内容,条目的绘制 invalidate(); //只会触发执行onDraw方法,但是可以在子线程中刷新 postInvalidate(); //vi ...

  8. Android自定义view之基础知识

    Android自定义view之基础知识 虽然Android已经自带了很多实用的view和layout,加以调教能实现很美观的界面,但是有一些情况下,需要实现特殊的界面效果,比如我们比较熟悉的各种播放器 ...

  9. Android 自定义View

    [Android 自定义View] Android 自定义View 自定义View基础 自定义TextView 继承View重写onDraw方法 View的构造方法 自定义属性 创建attrsxml文 ...

最新文章

  1. Raspberry Pi 4B 颜色检测
  2. WCF部署到IIS不使用svc文件
  3. Vue Router的详细教程
  4. 漫步最优化三十六——基本共轭方向法
  5. 任正非:不要过度消费客户及民众对我们的同情与支持
  6. 盘点国内外那些有野心的BI公司
  7. Python菜鸟入门:day08函数概念
  8. linux shell 获取用户名,shell脚本输出/etc/passwd中shell类型对应的用户名及其个数
  9. html 盒子写法,CSS盒子模型
  10. viewpage滑动查看图片并再有缩略图预览
  11. Mac 上删除用户或群组教程
  12. LINUX最好用查看端口占用并杀死(kill)的方式
  13. 51单片机定时器实现PWM波
  14. 训练序列与导频序列的概念辨析
  15. 【OD矩阵】《城市公交IC卡·数据分析方法及应用》利用公交运营时间和乘客刷卡时间特征识别上车点
  16. 转:: 刺鸟:用python来开发webgame服务端(1)
  17. 复杂网络作业四:第三题——随机图、小世界网络和真实网络的度分布
  18. win10安装.net framework 3.5 错误代码 错误代码 0x800F0906、0x800F081F、0x800F0907
  19. #微信小程序# 在小程序里面退出退出小程序(navigator以及API--wx.exitMiniProgram)
  20. 插鼠标出现 usb设备无法识别 解决办法

热门文章

  1. sql 查询结果横向拼接
  2. 【梯度下降】原理和过程(一)
  3. 【网络通信】websocket如何断线重连
  4. Leaflet基本用法
  5. 卷积神经网络中的池化(Pooling)层
  6. 关于中间件:谈谈中间件开发
  7. C语言 生成十个随机数并排序
  8. 不一样的Gradle多渠道配置总结2
  9. android用户苹果手表,CIRP:35%的美国iPhone用户拥有智能手表 是Android用户的两倍...
  10. 薪火相传:学生为我赋能