編輯:關於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 實現鬧鐘喚起播放鬧鐘鈴聲功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!
當我們在手機上安裝360安全衛士時,手機屏幕上時刻都會出現一個小浮動窗口,點擊該浮動窗口可跳轉到安全衛士的操作界面,而且該浮動窗口不受其他activity的覆蓋影響仍然可
1. 圖片縮放後對齊的問題 在Android的開發中,如何使用圖片對很多開發人員是一個很頭痛的事。最常見的問題是在一台手機上調試好的UI,在不同dpi的手機上會變形。
我用GridView來顯示一些字符串,而字符串的長度是不固定的,然後就遇到問題了:有時字符重疊,有時顯示不全,有時兩種問題同時出現。見下圖: 圖一 GridView顯示重
注:在Edittext和Textview中,不要加下面2個屬性中的任何一種。否則,當行數大於1行以後會發生表情、圖片對不齊的情況android:lineSpacingEx