Android简易音乐重构MVVM Java版-新增推荐菜单及侧边栏展示(十二)
关于
本篇主要实现主界面新增推荐歌单展示及侧滑栏菜单。
效果图
添加侧边栏
修改activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/home_drawer_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/boundary_gray"
tools:context=".ui.home.MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/view_top"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_60"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimary"
/>
<ImageView
android:id="@+id/home_top_left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_home_top_menu"
app:layout_constraintTop_toTopOf="@id/view_top"
app:layout_constraintBottom_toBottomOf="@id/view_top"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="@dimen/dp_12" />
<ImageView
android:id="@+id/search"
android:layout_width="@dimen/dp_22"
android:layout_height="@dimen/dp_25"
android:layout_marginEnd="@dimen/dp_16"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/music_mike"
app:layout_constraintTop_toTopOf="@id/view_top"
app:layout_constraintBottom_toBottomOf="@id/view_top" />
<EditText
android:id="@+id/ed_search"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_30"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginEnd="@dimen/dp_16"
app:layout_constraintStart_toEndOf="@id/home_top_left_btn"
app:layout_constraintEnd_toStartOf="@id/search"
app:layout_constraintTop_toTopOf="@id/view_top"
android:alpha="0.5"
android:textColor="@color/white"
android:paddingStart="@dimen/dp_8"
android:paddingEnd="@dimen/dp_8"
android:paddingTop="@dimen/dp_5"
android:paddingBottom="@dimen/dp_5"
app:layout_constraintBottom_toBottomOf="@id/view_top"
android:background="@drawable/bg_edit_search_gray" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/home_viewpager"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0"
app:layout_constraintTop_toBottomOf="@id/view_top"
app:layout_constraintBottom_toTopOf="@id/bottom_nav" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:background="?android:attr/windowBackground"
android:layout_height="@dimen/dp_60"
app:menu="@menu/bottom_nav"
app:itemRippleColor="@color/white"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!--添加DrawerMenuFragment作为侧滑栏页面-->
<fragment
android:name="com.tobery.personalmusic.ui.home.menu.DrawerMenuFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
tools:ignore="RtlHardcoded" />
</androidx.drawerlayout.widget.DrawerLayout>
新增DrawerMenuFragment.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
<View
android:id="@+id/view_title_bg"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_45"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimary" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/view_title_bg"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0"
android:paddingTop="@dimen/dp_45">
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
新增DrawerMenuFragment.java
:
public class DrawerMenuFragment extends Fragment {
private FragmentDrawberMenuBinding binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentDrawberMenuBinding.inflate(inflater);
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
binding.setLifecycleOwner(this);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
添加推荐歌单
修改DiscoverFragmentViewModel
,添加请求推荐歌单:
public LiveData<ApiResponse<MainRecommendListBean>> getRecommendList(){
return RetrofitUtils.getmApiUrl().getRecommendPlayList();
}
修改ApiService,添加推荐歌单api:
@GET("recommend/resource")
//推荐歌单
LiveData<ApiResponse<MainRecommendListBean>> getRecommendPlayList();
添加MainRecommendListBean实体类(后续轮播图和推荐歌单都要重构,暂时先用以前的代码):
/**
* 首页推荐歌单的ban
* Created By Tobey on 2020/9/10
*/
public class MainRecommendListBean {
private int code;
private boolean featureFirst;
private boolean haveRcmdSongs;
private List<RecommendBean> recommend;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public boolean isFeatureFirst() {
return featureFirst;
}
public void setFeatureFirst(boolean featureFirst) {
this.featureFirst = featureFirst;
}
public boolean isHaveRcmdSongs() {
return haveRcmdSongs;
}
public void setHaveRcmdSongs(boolean haveRcmdSongs) {
this.haveRcmdSongs = haveRcmdSongs;
}
public List<RecommendBean> getRecommend() {
return recommend;
}
public void setRecommend(List<RecommendBean> recommend) {
this.recommend = recommend;
}
public static class RecommendBean {
private long id;
private int type;
private String name;
private String copywriter;
private String picUrl;
private long playcount;
private long createTime;
private CreatorBean creator;
private int trackCount;
private int userId;
private String alg;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCopywriter() {
return copywriter;
}
public void setCopywriter(String copywriter) {
this.copywriter = copywriter;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public long getPlaycount() {
return playcount;
}
public void setPlaycount(int playcount) {
this.playcount = playcount;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public CreatorBean getCreator() {
return creator;
}
public void setCreator(CreatorBean creator) {
this.creator = creator;
}
public int getTrackCount() {
return trackCount;
}
public void setTrackCount(int trackCount) {
this.trackCount = trackCount;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getAlg() {
return alg;
}
public void setAlg(String alg) {
this.alg = alg;
}
public static class CreatorBean {
private String backgroundImgIdStr;
private Object remarkName;
private boolean mutual;
private int userId;
private long avatarImgId;
private int djStatus;
private boolean followed;
private String backgroundUrl;
private long backgroundImgId;
private String detailDescription;
private boolean defaultAvatar;
private Object expertTags;
private int accountStatus;
private int vipType;
private int province;
private int gender;
private String avatarUrl;
private int authStatus;
private int userType;
private String nickname;
private long birthday;
private int city;
private String avatarImgIdStr;
private String description;
private String signature;
private int authority;
public String getBackgroundImgIdStr() {
return backgroundImgIdStr;
}
public void setBackgroundImgIdStr(String backgroundImgIdStr) {
this.backgroundImgIdStr = backgroundImgIdStr;
}
public Object getRemarkName() {
return remarkName;
}
public void setRemarkName(Object remarkName) {
this.remarkName = remarkName;
}
public boolean isMutual() {
return mutual;
}
public void setMutual(boolean mutual) {
this.mutual = mutual;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public long getAvatarImgId() {
return avatarImgId;
}
public void setAvatarImgId(long avatarImgId) {
this.avatarImgId = avatarImgId;
}
public int getDjStatus() {
return djStatus;
}
public void setDjStatus(int djStatus) {
this.djStatus = djStatus;
}
public boolean isFollowed() {
return followed;
}
public void setFollowed(boolean followed) {
this.followed = followed;
}
public String getBackgroundUrl() {
return backgroundUrl;
}
public void setBackgroundUrl(String backgroundUrl) {
this.backgroundUrl = backgroundUrl;
}
public long getBackgroundImgId() {
return backgroundImgId;
}
public void setBackgroundImgId(long backgroundImgId) {
this.backgroundImgId = backgroundImgId;
}
public String getDetailDescription() {
return detailDescription;
}
public void setDetailDescription(String detailDescription) {
this.detailDescription = detailDescription;
}
public boolean isDefaultAvatar() {
return defaultAvatar;
}
public void setDefaultAvatar(boolean defaultAvatar) {
this.defaultAvatar = defaultAvatar;
}
public Object getExpertTags() {
return expertTags;
}
public void setExpertTags(Object expertTags) {
this.expertTags = expertTags;
}
public int getAccountStatus() {
return accountStatus;
}
public void setAccountStatus(int accountStatus) {
this.accountStatus = accountStatus;
}
public int getVipType() {
return vipType;
}
public void setVipType(int vipType) {
this.vipType = vipType;
}
public int getProvince() {
return province;
}
public void setProvince(int province) {
this.province = province;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public int getAuthStatus() {
return authStatus;
}
public void setAuthStatus(int authStatus) {
this.authStatus = authStatus;
}
public int getUserType() {
return userType;
}
public void setUserType(int userType) {
this.userType = userType;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public long getBirthday() {
return birthday;
}
public void setBirthday(long birthday) {
this.birthday = birthday;
}
public int getCity() {
return city;
}
public void setCity(int city) {
this.city = city;
}
public String getAvatarImgIdStr() {
return avatarImgIdStr;
}
public void setAvatarImgIdStr(String avatarImgIdStr) {
this.avatarImgIdStr = avatarImgIdStr;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public int getAuthority() {
return authority;
}
public void setAuthority(int authority) {
this.authority = authority;
}
}
}
}
新增RecommendAdapter适配器
添加布局item_recommend_discover.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/img_recommend"
android:layout_width="@dimen/dp_120"
android:layout_height="@dimen/dp_120"
android:layout_margin="@dimen/dp_8"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="fitXY" />
<TextView
android:id="@+id/recommend_title"
android:layout_width="@dimen/dp_120"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/tv_black"
android:textSize="@dimen/sp_12"
app:layout_constraintTop_toBottomOf="@id/img_recommend"
app:layout_constraintStart_toStartOf="@id/img_recommend"
app:layout_constraintEnd_toEndOf="@id/img_recommend" />
<TextView
android:id="@+id/play_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLength="1"
android:textColor="@color/white"
android:textSize="@dimen/sp_8"
app:layout_constraintTop_toTopOf="@id/img_recommend"
android:layout_marginTop="@dimen/dp_5"
app:layout_constraintEnd_toEndOf="@id/img_recommend"
android:layout_marginEnd="@dimen/dp_5" />
</androidx.constraintlayout.widget.ConstraintLayout>
新增RecommendAdapter.java
:
public class RecommendAdapter extends RecyclerView.Adapter<ViewHolder> {
private final List<MainRecommendListBean.RecommendBean> dataList = new ArrayList<>();
private final Context mContext;
private OnItemClick onItemClick;
public void setOnItemClick(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public RecommendAdapter(Context context) {
this.mContext = context;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemRecommendDiscoverBinding binding = ItemRecommendDiscoverBinding
.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolder(binding);
}
@SuppressLint("NotifyDataSetChanged")
public void setDataList(List<MainRecommendListBean.RecommendBean> data) {
dataList.clear();
dataList.addAll(data);
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
MainRecommendListBean.RecommendBean bean = dataList.get(position);
holder.tvTitle.setText(bean.getName());
holder.tvCount.setText(bean.getPlaycount() + "");
RequestOptions options = new RequestOptions()
.placeholder(R.drawable.ic_banner_loading)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.transform(new CenterCrop(),new RoundedCorners(10))
.error(R.mipmap.ic_launcher);
Glide.with(mContext)
.load(bean.getPicUrl())
.transition(new DrawableTransitionOptions().crossFade())
.apply(options)
.into(holder.imRecommend);
}
@Override
public int getItemCount() {
return dataList.size();
}
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle, tvCount;
ImageView imRecommend;
public ViewHolder(ItemRecommendDiscoverBinding binding) {
super(binding.getRoot());
tvTitle = binding.recommendTitle;
imRecommend = binding.imgRecommend;
tvCount = binding.playCount;
}
}
interface OnItemClick {
void onClick();
}
修改DiscoverFragment.java
public class DiscoverFragment extends Fragment {
private FragmentDiscoverBinding binding;
private DiscoverFragmentViewModel viewModel;
private RecommendAdapter adapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentDiscoverBinding.inflate(inflater,container,false);
viewModel = new ViewModelProvider(this).get(DiscoverFragmentViewModel.class);
binding.setLifecycleOwner(this);
binding.setVm(viewModel);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initRecycle();
initObserver();
}
private void initRecycle() {
adapter = new RecommendAdapter(getContext());
LinearLayoutManager manager = new LinearLayoutManager(getContext());
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
binding.recommendRecycle.setLayoutManager(manager);
binding.recommendRecycle.setHasFixedSize(true);
binding.recommendRecycle.setAdapter(adapter);
}
private void initObserver() {
viewModel.getBanner().observe(getViewLifecycleOwner(), banner_beanApiResponse -> {
if (banner_beanApiResponse.getStatus() == Status.SUCCESS){
initData(banner_beanApiResponse.getData().getBanners());
}
});
viewModel.getRecommendList().observe(getViewLifecycleOwner(), mainRecommendListBeanApiResponse -> {
if (mainRecommendListBeanApiResponse.getStatus() == Status.SUCCESS){
adapter.setDataList(mainRecommendListBeanApiResponse.getData().getRecommend());
}
});
}
private void initData(List<banner_bean.BannersBean> banners) {
binding.bannerImg.setAdapter(new bannerAdapter(banners))
.addBannerLifecycleObserver(getViewLifecycleOwner())
.setIntercept(false) //不拦截事件
.setBannerRound(10f)//圆角
.setIndicator(new RectangleIndicator(getContext())) //线条指示器
.setIndicatorHeight(5)
.setIndicatorWidth(6,6)//选中下宽度一致
.setIndicatorGravity(IndicatorConfig.Direction.CENTER)
.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(Object data, int position) {
}
});
}
}
本篇到此结束,有问题欢迎批评指正,觉得不错也请点个赞谢谢。