編輯:關於Android編程
先上圖看一下鬧鐘喚期頁面的效果



實現的功能:
1:轉動的圖片根據天氣情況更換
2:轉動時間可以設置,轉動結束,鬧鈴聲音就結束
3:光圈顏色漸變效果
直接上代碼啦:
package com.yuekong.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);
//最外層圓形的Paint
private Paint mOutCirclePaint;
//內圓的Paint
private Paint mInnerCirclePaint;
//標題Paint
private Paint mTitlePaint;
//漸變弧
private Paint mGradientArcPaint;
private SweepGradient mSweepGradient;
//日期時間Paint
private 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);
//外圓的paint
mOutCirclePaint = new Paint();
mOutCirclePaint.setAntiAlias(true);
mOutCirclePaint.setStyle(Paint.Style.STROKE);
mOutCirclePaint.setStrokeWidth(dp2px(5));
mOutCirclePaint.setColor(mOutCircleColor);
//內圓的Paint
mInnerCirclePaint = new Paint();
mInnerCirclePaint.setAntiAlias(true);
mInnerCirclePaint.setStyle(Paint.Style.STROKE);
mInnerCirclePaint.setStrokeWidth(dp2px(5));
mInnerCirclePaint.setColor(mInnerCircleColor);
//標題的Paint
mTitlePaint = new Paint();
mTitlePaint.setAntiAlias(true);
mTitlePaint.setStyle(Paint.Style.FILL);
mTitlePaint.setColor(mContext.getResources().getColor(R.color.nav_highlighted));
mTitlePaint.setTextSize(sp2px(14));
//時間的Paint
mTimePaint = new Paint();
mTimePaint.setAntiAlias(true);
mTimePaint.setColor(Color.WHITE);
mTimePaint.setStyle(Paint.Style.FILL);
mTimePaint.setTextSize(sp2px(70));
//日期的Paint
mDatePaint = new Paint();
mDatePaint.setAntiAlias(true);
mDatePaint.setColor(Color.WHITE);
mDatePaint.setStyle(Paint.Style.FILL);
mDatePaint.setTextSize(sp2px(14));
//漸變弧的Paint
mGradientArcPaint = 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);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = startMeasure(widthMeasureSpec);
mHeight = startMeasure(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected 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() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mCurrentAngle = (float) valueAnimator.getAnimatedValue() * 360;
invalidate();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if (mRingTone != null && mRingTone.isPlaying()) {
mRingTone.stop();
}
if (mCountdownListener != null) {
mCountdownListener.countdownFinished();
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public 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 實現鬧鐘喚起播放鬧鐘鈴聲功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!
android 類似360懸浮窗口實現源碼
當我們在手機上安裝360安全衛士時,手機屏幕上時刻都會出現一個小浮動窗口,點擊該浮動窗口可跳轉到安全衛士的操作界面,而且該浮動窗口不受其他activity的覆蓋影響仍然可
Android圖片資源的縮放問題
1. 圖片縮放後對齊的問題 在Android的開發中,如何使用圖片對很多開發人員是一個很頭痛的事。最常見的問題是在一台手機上調試好的UI,在不同dpi的手機上會變形。
解決GridView內容顯示不全問題
我用GridView來顯示一些字符串,而字符串的長度是不固定的,然後就遇到問題了:有時字符重疊,有時顯示不全,有時兩種問題同時出現。見下圖: 圖一 GridView顯示重
匹配表情、關鍵字、Url的Textview
注:在Edittext和Textview中,不要加下面2個屬性中的任何一種。否則,當行數大於1行以後會發生表情、圖片對不齊的情況android:lineSpacingEx