播放列表

This commit is contained in:
litingting 2024-09-27 19:10:02 +08:00
parent 0f59e337be
commit 129680cb45
23 changed files with 861 additions and 233 deletions

View File

@ -57,8 +57,13 @@ dependencies {
implementation("com.github.bumptech.glide:glide:4.16.0")
//提取图片主色
implementation ("androidx.palette:palette:1.0.0")
//动画
implementation ("com.airbnb.android:lottie:5.2.0")
//----------media3
implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-dash:1.4.1")

View File

@ -0,0 +1,51 @@
{
"v": "5.5.7",
"fr": 60,
"ip": 0,
"op": 90,
"w": 500,
"h": 500,
"nm": "Audio Wave",
"ddd": 0,
"assets": [],
"layers": [
{
"ddd": 0,
"ind": 1,
"ty": 4,
"nm": "Wave Layer",
"sr": 1,
"ks": {
"o": { "a": 0, "k": 100, "ix": 11 },
"r": { "a": 0, "k": 0, "ix": 10 },
"p": { "a": 0, "k": [250, 250, 0], "ix": 2 },
"a": { "a": 0, "k": [0, 0, 0], "ix": 1 },
"s": {
"a": 1,
"k": [
{ "i": { "x": [0.667], "y": [1] }, "o": { "x": [0.333], "y": [0] }, "t": 0, "s": [100, 100, 100] },
{ "i": { "x": [0.667], "y": [1] }, "o": { "x": [0.333], "y": [0] }, "t": 45, "s": [100, 150, 100] },
{ "t": 90, "s": [100, 100, 100] }
],
"ix": 6
}
},
"ao": 0,
"shapes": [
{
"ty": "rc",
"d": 1,
"s": { "a": 0, "k": [100, 300], "ix": 2 },
"p": { "a": 0, "k": [0, 0], "ix": 3 },
"nm": "Rectangle Path 1",
"mn": "ADBE Vector Shape - Rect",
"hd": false
}
],
"ip": 0,
"op": 90,
"st": 0,
"bm": 0
}
]
}

View File

@ -9,13 +9,11 @@ import com.hi.music.player.media3.MyMediaControllerManager;
public class MusicApplication extends Application {
// private final static MusicApplication sInstance = new MusicApplication();
public static Context myApplication;
// public static MusicApplication getInstance() {
// return sInstance;
// }

View File

@ -0,0 +1,59 @@
package com.hi.music.player.adapter;
import static androidx.media3.session.legacy.MediaControllerCompat.getMediaController;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.media3.common.MediaItem;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
import com.hi.music.player.databinding.ItemPlayListBinding;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.media3.MyMediaControllerManager;
public class AdapterPlayList extends BaseAdapter<ResponsePlayListInfo, ItemPlayListBinding> {
@Override
protected ItemPlayListBinding getViewBinding(ViewGroup parent) {
return ItemPlayListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ResponsePlayListInfo listInfo = data.get(position);
VHolder<ItemPlayListBinding> itemHolder = (VHolder<ItemPlayListBinding>) holder;
ItemPlayListBinding vb = itemHolder.getVb();
Glide.with(MusicApplication.myApplication)
.asDrawable()
.apply(RequestOptions.bitmapTransform(new RoundedCorners(CommonUtils.dpToPx(10))))
.load(listInfo.getSmallCovert())
.placeholder(R.mipmap.ic_launcher)
.into(vb.imCovert);
vb.songName.setText(listInfo.getSongTitle());
vb.artistName.setText(listInfo.getSingerName());
MyMediaControllerManager instance = MyMediaControllerManager.getInstance();
MediaItem currentMediaItem = instance.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null && currentMediaItem.mediaId.equals(listInfo.getVideoId())) {
vb.lottieAnimationView.setVisibility(View.VISIBLE);
if (instance.getMediaController().isPlaying()) {
vb.lottieAnimationView.playAnimation();
CommonUtils.LogMsg("-------playAnimation");
} else {
vb.lottieAnimationView.pauseAnimation();
CommonUtils.LogMsg("-------pauseAnimation");
}
} else {
vb.lottieAnimationView.setVisibility(View.GONE);
CommonUtils.LogMsg("-------GONE");
}
}
}

View File

@ -1,7 +1,9 @@
package com.hi.music.player.dialog;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -12,48 +14,80 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.viewbinding.ViewBinding;
import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
public abstract class BaseDialog<T extends ViewBinding> extends DialogFragment {
protected T vb;
protected abstract T getViewBinding(LayoutInflater inflater, ViewGroup container);
protected abstract T getViewBinding(LayoutInflater inflater, ViewGroup container);
protected abstract void initView();
protected abstract void initView();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
vb = getViewBinding(inflater,container);
vb = getViewBinding(inflater, container);
init();
initView();
return vb.getRoot();
}
@Override
public void onStart() {
super.onStart();
}
@SuppressLint("ResourceType")
private void init() {
Dialog dialog = getDialog();
setCancelable(true);
if (dialog != null) {
Window window = dialog.getWindow();
if (window != null) {
// window.setBackgroundDrawableResource();
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams attributes = window.getAttributes();
attributes.gravity = Gravity.BOTTOM;
attributes.width = WindowManager.LayoutParams.MATCH_PARENT;
attributes.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(attributes);
if (isFullScreen()) {
window.setStatusBarColor(Color.YELLOW); // 设置状态栏为透明或其他颜色
// 设置 dialog 占据全屏并延伸到状态栏
// window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
// 允许内容绘制到状态栏
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
window.setBackgroundDrawableResource(R.color.color_transparent);
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams attributes = window.getAttributes();
attributes.gravity = Gravity.BOTTOM;
attributes.width = WindowManager.LayoutParams.MATCH_PARENT;
attributes.height = WindowManager.LayoutParams.MATCH_PARENT;
window.setAttributes(attributes);
} else {
window.setBackgroundDrawableResource(R.color.color_transparent);
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams attributes = window.getAttributes();
attributes.gravity = Gravity.BOTTOM;
attributes.width = WindowManager.LayoutParams.MATCH_PARENT;
attributes.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(attributes);
}
}
}
}
public abstract boolean isFullScreen();
public void closeDialog() {
dismiss();
}

View File

@ -1,19 +1,126 @@
package com.hi.music.player.dialog;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hi.music.player.databinding.DialogPlayListBinding;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.UnstableApi;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
import com.hi.music.player.adapter.AdapterPlayList;
import com.hi.music.player.api.onImageColorListener;
import com.hi.music.player.databinding.DialogPlayListBinding;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.media3.MyControllerView;
import com.hi.music.player.media3.MyMediaControllerManager;
import java.util.List;
public class DialogPlayList extends BaseDialog<DialogPlayListBinding> {
private MyMediaControllerManager instance;
public class DialogPlayList extends BaseDialog<DialogPlayListBinding>{
@Override
protected DialogPlayListBinding getViewBinding(LayoutInflater inflater, ViewGroup container) {
return DialogPlayListBinding.inflate(inflater,container,false);
return DialogPlayListBinding.inflate(inflater, container, false);
}
@Override
protected void initView() {
instance = MyMediaControllerManager.getInstance();
initPlayListUi();
MediaItem currentMediaItem = instance.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null) {
Uri artworkUri = currentMediaItem.mediaMetadata.artworkUri;
vb.topSongName.setText(currentMediaItem.mediaMetadata.title);
vb.topSingerName.setText(currentMediaItem.mediaMetadata.artist);
Glide.with(MusicApplication.myApplication)
.asDrawable()
.apply(RequestOptions.bitmapTransform(new RoundedCorners(CommonUtils.dpToPx(10))))
.load(artworkUri)
.placeholder(R.mipmap.ic_launcher)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
CommonUtils.LogMsg(e.getMessage());
return false;
}
@OptIn(markerClass = UnstableApi.class)
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
CommonUtils.getDominantDarkColor1(resource, new onImageColorListener() {
@Override
public void onImageColor(int color) {
if (color == -1) {
return;
}
int lighterColor = CommonUtils.adjustBrightness(color, 1.2f); // 比原始颜色亮 20%
int darkerColor = CommonUtils.adjustBrightness(color, 0.8f); // 比原始颜色暗 20%
// GradientDrawable gradientDrawable = new GradientDrawable(
// GradientDrawable.Orientation.TOP_BOTTOM,
// new int[]{lighterColor, darkerColor} // 浅到深渐变
// );
vb.topLayout.setBackgroundColor(darkerColor);
Drawable newDrawable = CommonUtils.getNewDrawable(lighterColor, 24f, 24f, 0, 0);
vb.listLayout.setBackground(newDrawable);
}
});
return false;
}
})
.into(vb.topIm);
}
vb.imPlay.setSelected(instance.getMediaController().isPlaying());
vb.imPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
vb.imPlay.setSelected(!vb.imPlay.isSelected());
if (vb.imPlay.isSelected()) {
instance.play();
} else {
instance.pause();
}
}
});
}
@Override
public boolean isFullScreen() {
return true;
}
private void initPlayListUi() {
List<ResponsePlayListInfo> playList = instance.getPlayList();
AdapterPlayList adapterPlayList = new AdapterPlayList();
vb.recyclerList.setLayoutManager(new LinearLayoutManager(MusicApplication.myApplication));
adapterPlayList.addData(playList);
vb.recyclerList.setAdapter(adapterPlayList);
}

View File

@ -2,8 +2,10 @@ package com.hi.music.player.helper;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.ImageView;
@ -17,6 +19,8 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.ResponseBody;
@ -88,42 +92,74 @@ public class CommonUtils {
return String.format("%d:%02d", minutes, seconds); // 格式化为 mm:ss
}
/**
* 从图片中提取主色调
* @param imDraw
*/
public static void extractDominantColor(Drawable imDraw, onImageColorListener listener) {
BitmapDrawable drawable = (BitmapDrawable)imDraw;
if (drawable != null) {
Bitmap bitmap = drawable.getBitmap();
// 使用 Palette 提取颜色
Palette.from(bitmap).generate(palette -> {
if (palette != null) {
int dominantColor = palette.getDominantColor(0);
int suitableDarkColor = getSuitableDarkColor(dominantColor);
listener.onImageColor(suitableDarkColor);
// 使用 Palette 提取深色主色调
public static void getDominantDarkColor1(Drawable imDraw, onImageColorListener listener) {
// 异步生成 Palette
BitmapDrawable drawable = (BitmapDrawable)imDraw;
if(drawable!=null){
Bitmap bitmap = drawable.getBitmap();
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
// 首先尝试获取深色活力色
Palette.Swatch darkVibrantSwatch = palette.getDarkVibrantSwatch();
// 如果没有深色活力色尝试获取深色柔和色
if (darkVibrantSwatch == null) {
darkVibrantSwatch = palette.getDarkMutedSwatch();
}
// 如果存在深色样本则获取其 RGB 颜色值
if (darkVibrantSwatch != null) {
int dominantDarkColor = darkVibrantSwatch.getRgb();
listener.onImageColor(dominantDarkColor);
String dominantColorHex = String.format("#%06X", (0xFFFFFF & dominantDarkColor));
Log.d("Dominant Dark Color", "主色调: " + dominantColorHex); // 打印主色调
} else {
Log.d("Dominant Dark Color", "未找到深色主色调");
listener.onImageColor(-1);
}
}
});
}else {
listener.onImageColor(-1);
}
}
// 调整颜色的亮度factor > 1 表示变亮factor < 1 表示变暗
public static int adjustBrightness(int color, float factor) {
// RGB 颜色转换为 HSV
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
// 调整亮度V
hsv[2] = Math.min(1.0f, hsv[2] * factor); // 亮度值最多是 1.0
// 返回调整后的颜色HSV 转回 RGB
return Color.HSVToColor(hsv);
}
private static int getSuitableDarkColor(int color) {
// 提取颜色的 R, G, B
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = color & 0xff;
public static Drawable getNewDrawable(int color,float RadiusTopLeft,float RadiusTopRight,float RadiusBottomRight,float RadiusBottomLeft){
// 创建 GradientDrawable
GradientDrawable drawable = new GradientDrawable();
// 计算亮度
double luminance = 0.299 * r + 0.587 * g + 0.114 * b;
// 设置形状为矩形
drawable.setShape(GradientDrawable.RECTANGLE);
// 如果亮度较高则选择更深的颜色
if (luminance > 128) {
return 0xFF000000; // 黑色
} else {
// 如果颜色较暗选择一种深色调
return 0xFF1F1F1F; // 深灰色作为替代
}
// 设置背景颜色
drawable.setColor(color);
// 设置顶部圆角 (top-left and top-right)
float[] radii = new float[]{
RadiusTopLeft, RadiusTopLeft, // top-left radius
RadiusTopRight, RadiusTopRight, // top-right radius
RadiusBottomRight, RadiusBottomRight, // bottom-right radius
RadiusBottomLeft, RadiusBottomLeft // bottom-left radius
};
drawable.setCornerRadii(radii);
return drawable;
}
}

View File

@ -5,6 +5,13 @@ public class MyValue {
public static String KEY_PLAY_ACTIVITY_SINGER = "click_singer";
//播放错误
public static int PLAY_STATUS_CODE = -1;
public final static int PLAY_STATUS_CODE_ERROR = -1;
//正在播放
public final static int PLAY_STATUS_CODE_PLAYING = -2;
//暂停或者停止
public final static int PLAY_STATUS_CODE_PAUSE = -3;
//-----------------------------PlayActivity
}

View File

@ -24,10 +24,7 @@ import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.network.RetrofitManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
public class MyMediaControllerManager {
@ -82,7 +79,7 @@ public class MyMediaControllerManager {
@Override
public void onPlayerError(PlaybackException error) {
CommonUtils.LogMsg("=-----PlaybackException+" + error.getMessage());
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE);
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_ERROR);
}
@Override
@ -99,7 +96,7 @@ public class MyMediaControllerManager {
public void onIsPlayingChanged(boolean isPlaying) {
if (isPlaying) {
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PLAYING);
// TODO: 2024/9/26 自动播放完成切歌到下一首播放没有触发这里请求下一首
// 播放器开始播放
MediaItem currentItem = mediaController.getCurrentMediaItem();
@ -116,7 +113,7 @@ public class MyMediaControllerManager {
}
} else {
// 播放器暂停或停止
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PAUSE);
}
}
@ -185,6 +182,10 @@ public class MyMediaControllerManager {
this.playList = playList;
}
public List<ResponsePlayListInfo> getPlayList() {
return playList;
}
public void resetPlayList(){
mediaController.clearMediaItems();
}
@ -278,7 +279,10 @@ public class MyMediaControllerManager {
if (mediaController.isPlaying())
mediaController.pause();
}
public void stop() {
if (mediaController.isPlaying())
mediaController.stop();
}
public void playNext() {
if (mediaController.hasNextMediaItem()) {
mediaController.seekToNextMediaItem();

View File

@ -319,7 +319,7 @@ public class JsonHelper {
}
JSONArray jsonArray = jsonObject.getJSONObject("thumbnail").getJSONArray("thumbnails");
int length = jsonArray.length();
int index = 0;
int index = 3;
if(maxBig){
index = length - 1;
}

View File

@ -2,9 +2,13 @@ package com.hi.music.player.ui.activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Handler;
import android.util.Pair;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.SeekBar;
import androidx.annotation.NonNull;
@ -16,6 +20,7 @@ import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
@ -26,9 +31,11 @@ import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
import com.hi.music.player.adapter.AdapterPlayList;
import com.hi.music.player.api.MediaControllerListener;
import com.hi.music.player.api.onImageColorListener;
import com.hi.music.player.databinding.ActivityPlayBinding;
import com.hi.music.player.dialog.DialogPlayList;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.helper.MyValue;
import com.hi.music.player.javabean.CustomerUrlInfo;
@ -60,10 +67,12 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
private MyMediaControllerManager mediaControllerManager;
//请求播放列表是否成功
private boolean requestPlayList = false;
//请求第一首歌曲url是否成功
private boolean requestPlayUrl = false;
//播放列表ui初始化
private boolean initPlayList = false;
private GradientDrawable gradientDrawable;
private int lighterColor,darkerColor;
@Override
protected ActivityPlayBinding getViewBinding() {
@ -85,10 +94,10 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
@Override
public void onChanged(List<ResponsePlayListInfo> playList) {
if (playList == null) {
CommonUtils.LogMsg("---------playList = null");
return;
}
if (playList.size() > 0) {
requestPlayList = true;
mPlayList = playList;
musicInfo = playList.get(0);
@ -105,7 +114,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
CommonUtils.LogMsg("-------------需要马上播放这首歌曲,但是此次网络请求失败");
return;
}
requestPlayUrl = true;
mCurPlayInfo = customerUrlInfo.getPlayUrl();
int second = customerUrlInfo.getPlayMusicIndex();
boolean needPlayNow = customerUrlInfo.isNeedPlayNow();
@ -126,7 +135,19 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
private void initMediaController() {
mediaControllerManager = MyMediaControllerManager.getInstance();
mediaControllerManager.resetPlayList();
String videoId = responseSingle.getVideoId();
MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem();
if(currentMediaItem != null){
if(currentMediaItem.mediaId.equals(videoId)){
// TODO: 2024/9/27 正在播放当前歌曲又点进来
// mediaControllerManager.getMediaController().seekTo(0);
}
if(mediaControllerManager.getMediaController().isPlaying()){
mediaControllerManager.stop();
}
mediaControllerManager.resetPlayList();
}
mediaControllerManager.addListener(new MediaControllerListener() {
@Override
public void onPlayStatus(int playStatus) {
@ -156,6 +177,12 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
mediaControllerManager.playNext();
break;
case MyValue.PLAY_STATUS_CODE_PAUSE:
vb.btnPlay.setSelected(false);
break;
case MyValue.PLAY_STATUS_CODE_PLAYING:
vb.btnPlay.setSelected(true);
break;
}
}
@ -172,6 +199,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
@Override
public void onChangeMusic(MediaItem mediaItem) {
CommonUtils.LogMsg("111111111-------22222---"+mediaItem.mediaMetadata.title +"---id="+mediaItem.mediaId);
loadInfo(mediaItem);
}
@ -185,6 +213,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
vb.btnNext.setOnClickListener(this);
vb.btnPrevious.setOnClickListener(this);
vb.imBack.setOnClickListener(this);
vb.btnMusicList.setOnClickListener(this);
}
@ -221,7 +250,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
private void loadInfo(MediaItem mediaItem) {
MediaMetadata mediaMetadata = mediaItem.mediaMetadata;
CommonUtils.LogMsg("--------------加载当前播放歌曲信息 "+mediaMetadata.description);
CommonUtils.LogMsg("--------------加载当前播放歌曲信息 " + mediaMetadata.description);
if (mediaMetadata.artworkUri != null) {
loadCovert(mediaMetadata.artworkUri.toString());
}
@ -238,15 +267,6 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
}
/**
* 更新音频url到播放列表
*/
private void updateAudioUrl(ResponsePlayUrl playUrl) {
// mediaControllerManager.UpdateAudioUrl(playUrl);
}
private void loadCovert(String url) {
Glide.with(MusicApplication.myApplication)
.asDrawable()
@ -263,10 +283,19 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
@OptIn(markerClass = UnstableApi.class)
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
CommonUtils.extractDominantColor(resource, new onImageColorListener() {
CommonUtils.getDominantDarkColor1(resource, new onImageColorListener() {
@Override
public void onImageColor(int color) {
vb.rootLayout.setBackgroundColor(color);
if (color == -1) {
return;
}
lighterColor = CommonUtils.adjustBrightness(color, 1.2f); // 比原始颜色亮 20%
darkerColor = CommonUtils.adjustBrightness(color, 0.8f); // 比原始颜色暗 20%
gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{lighterColor, darkerColor} // 浅到深渐变
);
vb.rootLayout.setBackground(gradientDrawable);
}
});
@ -317,10 +346,94 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
mediaControllerManager.playPrevious();
} else if (v.equals(vb.imBack)) {
finish();
} else if (v.equals(vb.btnMusicList)) {
initShowPlayList(true);
} else if (v.equals(vb.layoutPlayList.imPlay)) {
vb.layoutPlayList.imPlay.setSelected(!vb.layoutPlayList.imPlay.isSelected());
if (vb.layoutPlayList.imPlay.isSelected()) {
mediaControllerManager.play();
} else {
mediaControllerManager.pause();
}
}
}
/**
* 控制播放列表的显示
*
* @param show
*/
private void initShowPlayList(boolean show) {
if (show) {
Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_up);
vb.layoutPlayList.linearLayout.startAnimation(animation);
vb.layoutPlayList.linearLayout.setVisibility(View.VISIBLE);
vb.contentLayout.setVisibility(View.GONE);
if (!initPlayList) {
List<ResponsePlayListInfo> playList = mediaControllerManager.getPlayList();
AdapterPlayList adapterPlayList = new AdapterPlayList();
vb.layoutPlayList.recyclerList.setLayoutManager(new LinearLayoutManager(MusicApplication.myApplication));
adapterPlayList.addData(playList);
vb.layoutPlayList.recyclerList.setAdapter(adapterPlayList);
vb.layoutPlayList.imPlay.setOnClickListener(this);
initPlayList = true;
}
MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null) {
Uri artworkUri = currentMediaItem.mediaMetadata.artworkUri;
vb.layoutPlayList.topSongName.setText(currentMediaItem.mediaMetadata.title);
vb.layoutPlayList.topSingerName.setText(currentMediaItem.mediaMetadata.artist);
vb.layoutPlayList.topLayout.setBackgroundColor(darkerColor);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{darkerColor, darkerColor}
);
vb.rootLayout.setBackground(gradientDrawable);
Drawable newDrawable = CommonUtils.getNewDrawable(lighterColor, 24f, 24f, 0, 0);
vb.layoutPlayList.listLayout.setBackground(newDrawable);
Glide.with(MusicApplication.myApplication)
.asDrawable()
.apply(RequestOptions.bitmapTransform(new RoundedCorners(CommonUtils.dpToPx(10))))
.load(artworkUri)
.placeholder(R.mipmap.ic_launcher)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
CommonUtils.LogMsg(e.getMessage());
return false;
}
@OptIn(markerClass = UnstableApi.class)
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.into(vb.layoutPlayList.topIm);
}
vb.layoutPlayList.imPlay.setSelected(mediaControllerManager.getMediaController().isPlaying());
} else {
vb.rootLayout.setBackground(gradientDrawable);
vb.contentLayout.setVisibility(View.VISIBLE);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_down);
vb.layoutPlayList.linearLayout.startAnimation(animation);
vb.layoutPlayList.linearLayout.setVisibility(View.GONE);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
@ -328,6 +441,14 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
mHandler.removeCallbacks(mRunnable);
}
@Override
public void onBackPressed() {
if (vb.layoutPlayList.linearLayout.getVisibility()==View.VISIBLE) {
initShowPlayList(false);
} else {
super.onBackPressed(); // 调用系统默认的返回行为
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

View File

@ -1,7 +1,5 @@
package com.hi.music.player.ui.activity.viewmodel;
import android.util.Pair;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
@ -40,6 +38,8 @@ public class VMPlay extends ViewModel {
String params = responseSingle.getParams();
String musicVideoType = responseSingle.getMusicVideoType();
CommonUtils.LogMsg("111111111-------0000---"+responseSingle.getSongTitle() +"---id="+videoId);
RetrofitManager.getInstance().getPlayList(params, playlistId, videoId, musicVideoType, new RequestListener<ResponseBody>() {
@Override
@ -54,6 +54,7 @@ public class VMPlay extends ViewModel {
List<ResponsePlayListInfo> responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject);
MyMediaControllerManager.getInstance().setPlayList(responsePlayListInfos);
_playList.setValue(responsePlayListInfos);
CommonUtils.LogMsg("111111111-------1111----"+responsePlayListInfos.get(0).getSongTitle() +"---id="+responsePlayListInfos.get(0).getVideoId());
getPlayUrl(responseSingle.getVideoId(),0,true);
} else {
_playList.setValue(null);
@ -78,6 +79,10 @@ public class VMPlay extends ViewModel {
JSONObject jsonObject = CommonUtils.toJsonObject(data);
if (jsonObject != null) {
ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
if(responsePlayUrl == null){
// TODO: 2024/9/27
return;
}
MyMediaControllerManager.getInstance().addMusicToPlayList(responsePlayUrl,playListIndex);
customerUrlInfo.setPlayUrl(responsePlayUrl);
customerUrlInfo.setPlayMusicIndex(playListIndex);

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="0%"
android:toYDelta="100%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%"
android:toYDelta="0%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:topLeftRadius="18dp" android:topRightRadius="18dp"/>
<solid android:color="@color/default_play_list_color"/>
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:drawable="@drawable/small_play"/>
<item android:state_selected="true" android:drawable="@drawable/small_pause"/>
</selector>

View File

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M17.571,2.57V21.57"
android:strokeWidth="5"
android:fillColor="#ffffff"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M6.429,2.57V21.57"
android:strokeWidth="5"
android:fillColor="#ffffff"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="26dp"
android:viewportWidth="26"
android:viewportHeight="26">
<path
android:pathData="M22.779,15.16L10.982,23.069C9.789,23.869 8.174,23.55 7.374,22.358C7.087,21.93 6.934,21.426 6.934,20.91V5.09C6.934,3.654 8.098,2.49 9.534,2.49C10.049,2.49 10.553,2.643 10.982,2.931L22.779,10.84C23.972,11.64 24.291,13.255 23.491,14.448C23.302,14.729 23.06,14.971 22.779,15.16Z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -1,103 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_layout"
android:background="@color/black"
tools:context=".ui.activity.PlayActivity">
<ImageView
android:id="@+id/im_back"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginStart="16dp"
android:layout_marginTop="25dp"
android:padding="9dp"
android:src="@drawable/arrow_bottom"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/im_covert"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginStart="40dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="40dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back" />
android:id="@+id/content_layout"
android:layout_height="match_parent">
<ImageView
android:id="@+id/im_back"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginStart="16dp"
android:layout_marginTop="25dp"
android:padding="9dp"
android:src="@drawable/arrow_bottom"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/im_covert"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginStart="40dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="40dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back" />
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back"
app:show_buffering="when_playing"
app:show_shuffle_button="true" />
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back"
app:show_buffering="when_playing"
app:show_shuffle_button="true" />
<ProgressBar
android:id="@+id/progressBarLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/im_covert"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toTopOf="@id/im_covert" />
<ProgressBar
android:id="@+id/progressBarLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/im_covert"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toTopOf="@id/im_covert" />
<TextView
android:id="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:text="@string/app_name"
android:textColor="@color/text_color_1"
android:textSize="19sp"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintTop_toBottomOf="@id/im_covert" />
<TextView
android:id="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:text="@string/app_name"
android:textColor="@color/text_color_1"
android:textSize="19sp"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintTop_toBottomOf="@id/im_covert" />
<TextView
android:id="@+id/tv_singer_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:text="@string/app_name"
android:textColor="@color/white_60_color"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="@id/tv_song_name"
app:layout_constraintTop_toBottomOf="@id/tv_song_name" />
<TextView
android:id="@+id/tv_singer_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:text="@string/app_name"
android:textColor="@color/white_60_color"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="@id/tv_song_name"
app:layout_constraintTop_toBottomOf="@id/tv_song_name" />
<!-- <com.google.android.material.slider.Slider-->
<!-- android:id="@+id/play_progress"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:value="0"-->
<!-- android:valueFrom="0"-->
<!-- android:valueTo="100"-->
<!-- app:labelBehavior="gone"-->
<!-- app:layout_constraintLeft_toLeftOf="parent"-->
<!-- app:layout_constraintRight_toRightOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_singer_name"-->
<!-- app:thumbColor="@color/white"-->
<!-- app:thumbElevation="0dp"-->
<!-- android:paddingStart="0dp"-->
<!-- android:paddingEnd="0dp"-->
<!-- app:thumbRadius="4dp"-->
<!-- app:trackColorActive="@color/white"-->
<!-- app:trackColorInactive="@color/seek_bg_color"-->
<!-- app:trackHeight="3dp" />-->
<SeekBar
android:id="@+id/play_progress"
android:layout_width="0dp"
@ -106,10 +92,10 @@
android:layout_marginTop="25dp"
android:layout_marginEnd="35dp"
android:maxHeight="3dp"
android:paddingStart="5dp"
android:paddingLeft="0dp"
android:paddingEnd="5dp"
android:paddingRight="0dp"
android:paddingStart="5dp"
android:progress="30"
android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/seekbar_thumb"
@ -118,82 +104,86 @@
app:layout_constraintTop_toBottomOf="@id/tv_singer_name" />
<ProgressBar
android:id="@+id/progressBar_buffer"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="3dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:progress="100"
android:progressDrawable="@drawable/horizontal_progressbar"
app:layout_constraintBottom_toBottomOf="@id/play_progress"
app:layout_constraintLeft_toLeftOf="@id/play_progress"
app:layout_constraintRight_toRightOf="@id/play_progress"
app:layout_constraintTop_toTopOf="@id/play_progress" />
<ProgressBar
android:id="@+id/progressBar_buffer"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="3dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:progress="100"
android:progressDrawable="@drawable/horizontal_progressbar"
app:layout_constraintBottom_toBottomOf="@id/play_progress"
app:layout_constraintLeft_toLeftOf="@id/play_progress"
app:layout_constraintRight_toRightOf="@id/play_progress"
app:layout_constraintTop_toTopOf="@id/play_progress" />
<TextView
android:id="@+id/tv_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingStart="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintStart_toStartOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<TextView
android:id="@+id/tv_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingStart="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintStart_toStartOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingEnd="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintEnd_toEndOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingEnd="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintEnd_toEndOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<ImageView
android:id="@+id/btn_play"
android:layout_width="66dp"
android:layout_height="66dp"
android:layout_marginTop="15dp"
android:src="@drawable/selector_icon_play"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_duration" />
<ImageView
android:id="@+id/btn_play"
android:layout_width="66dp"
android:layout_height="66dp"
android:layout_marginTop="15dp"
android:src="@drawable/selector_icon_play"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_duration" />
<ImageView
android:id="@+id/btn_previous"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="36dp"
android:src="@mipmap/icon_previous_true"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintEnd_toStartOf="@id/btn_play"
app:layout_constraintTop_toTopOf="@id/btn_play" />
<ImageView
android:id="@+id/btn_previous"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="36dp"
android:src="@mipmap/icon_previous_true"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintEnd_toStartOf="@id/btn_play"
app:layout_constraintTop_toTopOf="@id/btn_play" />
<ImageView
android:id="@+id/btn_next"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="36dp"
android:src="@mipmap/icon_next_true"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintStart_toEndOf="@id/btn_play"
app:layout_constraintTop_toTopOf="@id/btn_play" />
<ImageView
android:id="@+id/btn_next"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="36dp"
android:src="@mipmap/icon_next_true"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintStart_toEndOf="@id/btn_play"
app:layout_constraintTop_toTopOf="@id/btn_play" />
<ImageView
android:id="@+id/btn_music_list"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/icon_list"
app:layout_constraintTop_toTopOf="@id/btn_play"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@id/btn_next" />
<ImageView
android:id="@+id/btn_music_list"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/icon_list"
app:layout_constraintBottom_toBottomOf="@id/btn_play"
app:layout_constraintLeft_toRightOf="@id/btn_next"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_play" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<include
android:id="@+id/layout_playList"
layout="@layout/dialog_play_list" />
</FrameLayout>

View File

@ -1,9 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/top_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:paddingBottom="25dp">
<ImageView
android:id="@+id/top_im"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="10dp"
android:src="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/top_im"
android:layout_alignBottom="@id/top_im"
android:layout_marginStart="15dp"
android:layout_toStartOf="@id/im_play"
android:layout_toEndOf="@id/top_im"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingEnd="15dp">
<TextView
android:id="@+id/top_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/app_name"
android:textColor="@color/text_color_1"
android:textSize="14sp" />
<TextView
android:id="@+id/top_singer_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/white_60_color"
android:textSize="11sp" />
</LinearLayout>
<ImageView
android:id="@+id/im_play"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="42dp"
android:src="@drawable/selector_small_play" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/list_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-15dp"
android:background="@drawable/rec_bg_18">
<TextView
android:id="@id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="17sp"
android:layout_marginTop="10dp"
android:layout_marginStart="15dp"
android:textColor="@color/white"
android:text="@string/play_next" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingStart="20dp">
<ImageView
android:layout_width="60dp"
android:id="@+id/im_covert"
android:layout_centerVertical="true"
android:layout_height="60dp" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottieAnimationView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:padding="5dp"
android:layout_alignTop="@id/im_covert"
android:layout_alignBottom="@id/im_covert"
android:layout_alignStart="@id/im_covert"
android:layout_alignEnd="@id/im_covert"
app:lottie_fileName="music_bounce.json"
app:lottie_autoPlay="false"
app:lottie_loop="true"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/im_covert"
android:layout_marginStart="12dp"
android:layout_centerVertical="true"
android:orientation="vertical">
<TextView
android:id="@+id/song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textColor="@color/text_color_1"
android:textSize="14sp" />
<TextView
android:id="@+id/artist_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="@string/app_name"
android:textColor="@color/white_60_color"
android:textSize="11sp" />
</LinearLayout>
</RelativeLayout>

View File

@ -9,6 +9,7 @@
<color name="seek_bg_color">#4DFFFFFF</color>
<color name="white_60_color">#99FFFFFF</color>
<color name="progress_buffer_color">#59FFFFFF</color>
<color name="default_play_list_color">#1A1A1A</color>
<color name="test">#2D9C31</color>
</resources>

View File

@ -21,4 +21,5 @@
<string name="share">Share</string>
<string name="privacy_policy">Privacy Policy</string>
<string name="terms_of_service">Terms of Service</string>
<string name="play_next">Play next</string>
</resources>