冥想背景音乐功能

知识点:自定义控件,MediaPlayer,Ripple水波纹效果,CardView
自己计划的app在github上面很久了,一直没有什么进展,后来发现是自己想多了,计划太多感觉好难啊以后在看,就是没有行动,好几个月了.日拱一卒 不期速成,先开始做吧,虽然感觉自己的代码博客真的不好,不过谁是完美的,先第一版,慢慢迭代完美了.
冥想功能,最近2个月喜欢冥想,喜欢用番茄钟工作,所以需要下载不少app,都是比较成熟的,但是总会有自己的想法,一个Android程序员那就自己实现自己的想法吧"因为有用所以有用"我最喜欢的话,所以多用了
目的:1.提高代码水平,时间充足没有公司上线压力也不需要过于关注ui(原谅我自己app的ui确实不好),可以好好写更加关注用户看不到的代码本身质量
2.研究明白知识点,不能只是会用了,不然面试真的说不出多深入的
3.使用新技术,在公司一般为了安全很少使用新技术,自己的当然怎么新怎么来,各种尝试了
4.满足自己的需求了,用自己的app感觉很爽.

一图胜千言,主要功能下两图


1.jpg

2.jpg

主要功能,
1.音乐播放器(MediaPlayer) 开始停止等
2.选择背景音乐类型(保存assets),播放时间(Select选择或者输入EditText输入)
3.自定义view,播放的进度,四部分组成中间时间,圆形,第一个圆弧,第二个圆弧(耗时最多,也是最有意思的,毕竟自定义控件才是难点了)

代码
1.音乐播放器MediaPlayer
//播放器资源的准备工作 private void initMediaPlayer() { try { mAssets = this.getAssets(); //获取音乐文件 AssetFileDescriptor fileDescriptor = mAssets.openFd(musics[selectMusic]); //获取到播放类 mediaPlayer = new MediaPlayer(); //配置数据源 mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength()); //准备 mediaPlayer.prepare(); } catch (IOException e) { e.printStackTrace(); } //监听播放结束,循环播放,音乐文件可能过短需要循环 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (!isPlayer) { mediaPlayer.start(); } else { } } } ); }
开始停止音乐播放
case R.id.start: isPlayer = true; initMediaPlayer(); if (!mediaPlayer.isPlaying()) { String s = mTime.getText().toString(); playerAllTime = Integer.parseInt(s) * 60; //播放 mediaPlayer.start(); //开启计时器 handler.postDelayed(runnable, 1000); } break; case R.id.stop: isPlayer = false; if (mediaPlayer != null&&mediaPlayer.isPlaying()) { mediaPlayer.reset(); initMediaPlayer(); }
退出,关闭资源
@Override public void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.stop(); //释放播放器资源,一般再服务退出时执行 mediaPlayer.release(); } }
2.选择背景音乐类型(保存assets),播放时间(Select选择或者输入EditText输入)
直接2个自定义Dialog完成,RecyclerView要自己实现点击事件确实麻烦,不过效率更高
最上面CardView完全为了使用一下,以前都是自己绘制shape的直接用google提供的更简单一些
3.自定义view,核心部分,直接上代码,注释应该很完善了

`package w.com.wk.freelife.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

//自定义圆弧
public class ArcView extends View {
private Paint mArcPaint, mCirclePaint, mTextPaint, mPaint;
private float length;

private float mRadius;

private float mCircleXY;

private float mSweepValue = 0;
private String mShowText = "0";

private RectF mRectF;

public ArcView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initView();
}

public ArcView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView();
}

public ArcView(Context context) {
    super(context);
    initView();
}

private void initView() {

    //圆形颜色
    mCirclePaint = new Paint();
    mCirclePaint.setColor(Color.parseColor("#E2E2E2"));
    mCirclePaint.setAntiAlias(true);

    //字体颜色
    mTextPaint = new Paint();
    mTextPaint.setTextSize(40);
    mTextPaint.setAntiAlias(true);
    mTextPaint.setColor(Color.parseColor("#2F2F2F"));
    mTextPaint.setStrokeWidth(0);


    //画弧线1
    mPaint = new Paint();
    mPaint.setStrokeWidth(20);
    mPaint.setAntiAlias(true);
    mPaint.setColor(Color.parseColor("#ffffff"));
    mPaint.setStyle(Paint.Style.STROKE);

//画弧线2
mArcPaint = new Paint();
mArcPaint.setStrokeWidth(20);
mArcPaint.setAntiAlias(true);
mArcPaint.setColor(Color.parseColor("#00AAFE"));
mArcPaint.setStyle(Paint.Style.STROKE);

}

//android 系统回调onSizeChange获取宽度,确定半径等值
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    length = w;
    mCircleXY = length / 2;
    mRadius = (float) (length * 0.5 / 2);

}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 画圆

    //x,y位置自定义view的中心点,mRadius半径
    canvas.drawCircle(mCircleXY, mCircleXY, mRadius+160, mCirclePaint);

// // 画弧线oval :指定圆弧的外轮廓矩形区域。
// startAngle: 圆弧起始角度,单位为度。
// sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。
// useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。
// paint: 绘制圆弧的画板属性,如颜色,是否填充等。
//绘制圆弧的四个点
mRectF = new RectF((float) (length 0.2), (float) (length 0.2),
(float) (length 0.8), (float) (length 0.8));
canvas.drawArc(mRectF, 0, 360, false, mPaint);
canvas.drawArc(mRectF, 270, mSweepValue, false, mArcPaint);
// // 绘制文字
//测量字体宽度,我们需要根据字体的宽度设置在圆环中间
float textWidth = mTextPaint.measureText(mShowText);
canvas.drawText(mShowText, mCircleXY- textWidth / 2, mCircleXY, mTextPaint);

}

public void setProgress(float mSweepValue, int n) {
    float a = mSweepValue;
    if (a != 0) {
        this.mSweepValue = (float) (360.0 * a);
        mShowText = getTime(n);
    } else {
        this.mSweepValue = 0;
        mShowText = 0 + "";
    }

// postInvalidate invalidate都是实现界面刷新区别如下
// postInvalidate() 用在子线程向UI线程发送界面刷新消息请求,
// invalidate()调用直接在UI线程刷新界面, 子线程使用需要实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
// 使用postInvalidate最简单,内部封装了和ui线程的操作
invalidate();
}

//秒转换成为分钟:秒
public String getTime(int time) {
    if (time <= 0) {
        return "0:00";
    }

    int minute = time / 60 % 60;
    int second = time % 60;

    return minute + ":" + second;

}

}`

Android RectF类的构造函数参数说明 ,一直使用但是这次深入研究才真正想明白,左上右下的意思,都是距离x,y轴的距离罢了
上图
public RectF (float left, float top, float right, float bottom)
比如new一个RecF类:
RectF rf1 = new RectF(100,100,200,200);
则在屏幕中的位置示意图为:


先这么多,不是很完美,选择时间音乐地方太丑了,这几天研究下最新的动画,换个动画玩玩.
项目地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值