android:text=“扫描本地音乐”
android:textSize=“@dimen/sp_14”
android:theme=“@style/Theme.MaterialComponents.Light.NoActionBar”
app:backgroundTint=“@color/transparent”
app:cornerRadius=“@dimen/dp_20”
app:strokeColor=“@color/white”
app:strokeWidth=“@dimen/dp_1” />
<androidx.recyclerview.widget.RecyclerView
android:id=“@+id/rv_music”
android:layout_width=“match_parent”
android:layout_height=“match_parent” />
<com.google.android.material.button.MaterialButton
android:id=“@+id/btn_location_play_music”
style=“@style/Widget.MaterialComponents.Button.UnelevatedButton”
android:layout_width=“@dimen/dp_28”
android:layout_height=“@dimen/dp_28”
android:layout_above=“@+id/lay_bottom”
android:layout_alignParentRight=“true”
android:layout_margin=“@dimen/dp_36”
android:insetLeft=“@dimen/dp_0”
android:insetTop=“@dimen/dp_0”
android:insetRight=“@dimen/dp_0”
android:insetBottom=“@dimen/dp_0”
android:onClick=“onClick”
android:textSize=“@dimen/sp_14”
android:theme=“@style/Theme.MaterialComponents.Light.NoActionBar”
android:visibility=“gone”
app:backgroundTint=“@color/white”
app:cornerRadius=“@dimen/dp_20”
app:icon=“@drawable/music_location”
app:iconGravity=“textStart”
app:iconPadding=“0dp”
app:iconTint=“@color/black” />
<LinearLayout
android:id=“@+id/lay_bottom”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_alignParentBottom=“true”
android:background=“@color/bottom_bg_color”
android:gravity=“center_vertical”
android:paddingLeft=“@dimen/dp_8”
android:paddingTop=“@dimen/dp_8”
android:paddingRight=“@dimen/dp_16”
android:paddingBottom=“@dimen/dp_8”>
<RelativeLayout
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”>
<com.google.android.material.imageview.ShapeableImageView
android:id=“@+id/iv_logo”
android:layout_width=“@dimen/dp_48”
android:layout_height=“@dimen/dp_48”
android:padding=“1dp”
android:src=“@mipmap/icon_music”
app:shapeAppearanceOverlay=“@style/circleImageStyle”
app:strokeColor=“@color/white”
app:strokeWidth=“@dimen/dp_2” />
<com.llw.goodmusic.view.MusicRoundProgressView
android:id=“@+id/music_progress”
android:layout_width=“@dimen/dp_48”
android:layout_height=“@dimen/dp_48”
app:radius=“20dp”
app:strokeColor=“@color/black”
app:strokeWidth=“2dp” />
<com.google.android.material.textview.MaterialTextView
android:id=“@+id/tv_song_name”
android:layout_width=“0dp”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:ellipsize=“marquee”
android:focusable=“true”
android:focusableInTouchMode=“true”
android:marqueeRepeatLimit=“marquee_forever”
android:paddingLeft=“@dimen/dp_12”
android:paddingRight=“@dimen/dp_12”
android:singleLine=“true”
android:text=“Good Music”
android:textColor=“@color/white”
android:textSize=“@dimen/sp_16” />
<com.google.android.material.button.MaterialButton
android:id=“@+id/btn_play”
android:layout_width=“@dimen/dp_36”
android:layout_height=“@dimen/dp_36”
android:insetLeft=“@dimen/dp_0”
android:insetTop=“@dimen/dp_0”
android:insetRight=“@dimen/dp_0”
android:insetBottom=“@dimen/dp_0”
android:onClick=“onClick”
android:theme=“@style/Theme.MaterialComponents.Light.NoActionBar”
app:backgroundTint=“@color/transparent”
app:cornerRadius=“@dimen/dp_18”
app:icon=“@mipmap/icon_play”
app:iconGravity=“textStart”
app:iconPadding=“@dimen/dp_0”
app:iconSize=“@dimen/dp_36” />
里面用到三个图标一个自定义View。图标你可以去我的源码里面拿,源码图标,自定义View我会写出来。在com.llw.goodmusic下新建一个view包,然后新建一个MusicRoundProgressView。
代码如下:
package com.llw.goodmusic.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.llw.goodmusic.R;
/**
-
圆形进度条
-
@author llw
*/
public class MusicRoundProgressView extends View {
/**
- 画笔
*/
private Paint mPaint;
/**
- 画笔颜色
*/
private int mPaintColor;
/**
- 半径
*/
private float mRadius;
/**
- 圆环半径
*/
private float mRingRadius;
/**
- 圆环宽度
*/
private float mStrokeWidth;
/**
- 圆心 X 轴坐标
*/
private int mCenterX;
/**
- 圆心 Y 轴坐标
*/
private int mCenterY;
/**
- 总进度
*/
private int mTotalProgress;
/**
- 当前进度
*/
private int mProgress;
public MusicRoundProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressView);
//半径
mRadius = typedArray.getDimension(R.styleable.RoundProgressView_radius, 40);
//宽度
mStrokeWidth = typedArray.getDimension(R.styleable.RoundProgressView_strokeWidth, 5);
//颜色
mPaintColor = typedArray.getColor(R.styleable.RoundProgressView_strokeColor, 0xFFFFFFFF);
//圆环半径 = 半径 + 圆环宽度的1/2
mRingRadius = mRadius + mStrokeWidth / 2;
//画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(mPaintColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
}
@Override
protected void onDraw(Canvas canvas) {
mCenterX = getWidth() / 2;
mCenterY = getHeight() / 2;
if (mProgress > 0) {
RectF rectF = new RectF();
rectF.left = (mCenterX - mRingRadius);
rectF.top = (mCenterY - mRingRadius);
rectF.right = mRingRadius * 2 + (mCenterX - mRingRadius);
rectF.bottom = mRingRadius * 2 + (mCenterY - mRingRadius);
canvas.drawArc(rectF, -90, ((float) mProgress / mTotalProgress) * 360, false, mPaint);
}
}
/**
- 设置进度
*/
public void setProgress(int progress, int totalProgress) {
mProgress = progress;
mTotalProgress = totalProgress;
//重绘
postInvalidate();
}
}
里面涉及到的样式如下:
在styles.xml中增加如下代码:
现在你的自定义从理论上来说就不会报错了。当然可能需要改一下包名之类,下面就是回到LocalMusicActivty。
首先在当前定位按钮后面加上这些变量
/**
- 底部logo图标,点击之后弹出当前播放歌曲详情页
*/
private ShapeableImageView ivLogo;
/**
- 底部当前播放歌名
*/
private MaterialTextView tvSongName;
/**
- 底部当前歌曲控制按钮, 播放和暂停
*/
private MaterialButton btnPlay;
/**
- 音频播放器
*/
private MediaPlayer mediaPlayer;
/**
- 记录当前播放歌曲的位置
*/
public int mCurrentPosition = -1;
/**
- 自定义进度条
*/
private MusicRoundProgressView musicProgress;
/**
- 音乐进度间隔时间
*/
private static final int INTERNAL_TIME = 1000;
/**
- 图片动画
*/
private ObjectAnimator logoAnimation;
每一个都有注释,然后绑定相关的控件
同样点击事件必不可少
常规的操作是通过点击音乐列表中的某一首歌之后播放歌曲。还记得列表的点击事件在哪里吗?当然是在**showLocalMusicData()**方法里面,之前在这个方法中设置适配器和列表的一些相关属性和数据,当然还有点击事件。
回顾一下这个代码:
//item的点击事件
mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
if (view.getId() == R.id.item_music) {
if (oldPosition == -1) {
//未点击过 第一次点击
oldPosition = position;
mList.get(position).setCheck(true);
} else {
//大于 1次
if (oldPosition != position) {
mList.get(oldPosition).setCheck(false);
mList.get(position).setCheck(true);
//重新设置位置,当下一次点击时position又会和oldPosition不一样
oldPosition = position;
}
}
mAdapter.changeState();
}
}
});
我不想这里面的代码太多,所以我新写了一个方法。
/**
-
控制播放位置
-
@param position
*/
private void playPositionControl(int position) {
if (oldPosition == -1) {
//未点击过 第一次点击
oldPosition = position;
mList.get(position).setCheck(true);
} else {
//大于 1次
if (oldPosition != position) {
mList.get(oldPosition).setCheck(false);
mList.get(position).setCheck(true);
//重新设置位置,当下一次点击时position又会和oldPosition不一样
oldPosition = position;
}
}
mAdapter.changeState();
}
当点击这个item时将position传递给全局变量mCurrentPosition。
然后通过changeSong(mCurrentPosition);方法来播放歌曲
/**
- 切换歌曲
*/
private void changeSong(int position) {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
try {
//切歌前先重置,释放掉之前的资源
mediaPlayer.reset();
BLog.i(TAG, mList.get(position).path);
//设置播放音频的资源路径
mediaPlayer.setDataSource(mList.get(position).path);
//设置播放的歌名和歌手
tvSongName.setText(mList.get(position).song + " - " + mList.get(position).singer);
//如果内容超过控件,则启用跑马灯效果
tvSongName.setSelected(true);
//开始播放前的准备工作,加载多媒体资源,获取相关信息
mediaPlayer.prepare();
//开始播放音频
mediaPlayer.start();
//播放按钮控制
if (mediaPlayer.isPlaying()) {
btnPlay.setIcon(getDrawable(R.mipmap.icon_pause));
btnPlay.setIconTint(getColorStateList(R.color.gold_color));
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
(img-epX4xLgE-1711915243718)]
[外链图片转存中…(img-LKi6CrFr-1711915243718)]
[外链图片转存中…(img-qxFOmQx8-1711915243718)]
[外链图片转存中…(img-yHbduLai-1711915243719)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-7OUmUXJL-1711915243719)]
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。