Android简易音乐重构MVVM Java版-新增looklive+用户vip等级动画展示(十四)

关于

  本篇主要实现新增look live列表展示、加载网易云会员动态等级效果。

效果图

在这里插入图片描述

vip效果图

新增looklive适配器(LookAdapter)

public class LookAdapter extends RecyclerView.Adapter<LookViewHolder> {

    private final List<LookLiveEntity> dataList = new ArrayList<>();

    private final Context mContext;

    private OnItemClick onItemClick;

    public void setOnItemClick(OnItemClick onItemClick) {
        this.onItemClick = onItemClick;
    }

    public LookAdapter(Context context) {
        this.mContext = context;
    }

    @NonNull
    @Override
    public LookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemRecommendDiscoverBinding binding = ItemRecommendDiscoverBinding
                .inflate(LayoutInflater.from(parent.getContext()), parent, false);
        return new LookViewHolder(binding);
    }

    @SuppressLint("NotifyDataSetChanged")
    public void setDataList(List<LookLiveEntity> data) {
        dataList.clear();
        dataList.addAll(data);
        notifyDataSetChanged();
    }

    @Override
    public void onBindViewHolder(@NonNull LookViewHolder holder, int position) {
        LookLiveEntity bean = dataList.get(position);
        holder.tvTitle.setText(bean.getTitle());
        //holder.tvCount.setText(bean.getResources().get(0).getResourceExtInfo().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.getVerticalCover())
                .transition(new DrawableTransitionOptions().crossFade())
                .apply(options)
                .into(holder.imRecommend);

    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }
}

class LookViewHolder extends RecyclerView.ViewHolder {
    TextView tvTitle, tvCount;
    ImageView imRecommend;

    public LookViewHolder(ItemRecommendDiscoverBinding binding) {
        super(binding.getRoot());
        tvTitle = binding.recommendTitle;
        imRecommend = binding.imgRecommend;
        tvCount = binding.playCount;
    }
}

新增LookLiveEntity实体类

@NoArgsConstructor
@Data
public class LookLiveEntity {
    private int liveId;
    private String title;
    private double anchorId;
    private long coverId;
    private String cover;
    private LiveUrlEntity liveUrl;
    private Object playBackUrl;
    private int orientationScope;
    private int onlineNumber;
    private int liveStatus;
    private long startTime;
    private int endTime;
    private int roomId;
    private Object channelId;
    private int liveType;
    private int appKeyType;
    private int type;
    private int startStreamTag;
    private int agoraRoomNo;
    private String bgCoverUrl;
    private Object backgroundAnimateUrl;
    private int rtcSupplierType;
    private int popularity;
    private long verticalCoverId;
    private String verticalCover;
    private UserInfoEntity userInfo;
    private RecLiveDTOEntity recLiveDTO;
    private String coverTag;
    private String privateTag;
    private Object borderTag;
    private String startStreamTagName;
    private Object tags;
    private Object dynamicCover;
    private List<String> audioCoverIds;
    private SupplementParamToClientEntity supplementParamToClient;
    private CloudMusicMyFollowRecInfoEntity cloudMusicMyFollowRecInfo;
    private Object adSpreadDto;

    @NoArgsConstructor
    @Data
    public static class LiveUrlEntity {
        private String httpPullUrl;
        private String hlsPullUrl;
        private String rtmpPullUrl;
    }

    @NoArgsConstructor
    @Data
    public static class UserInfoEntity {
        private double userId;
        private String nickname;
        private String avatarUrl;
        private int authStatus;
        private int userType;
        private Object authName;
        private int liveRoomNo;
        private int vipType;
        private int gender;
        private Object artistName;
    }

    @NoArgsConstructor
    @Data
    public static class RecLiveDTOEntity {
        private String skipUrl;
        private String typeDesc;
        private int cardType;
        private String alg;
        private String anchorId;
        private int liveRoomNo;
        private int songId;
        private int accompanimentId;
        private SupplemetParamEntity supplemetParam;
        private String ops;
        private long recCoverId;
        private String recCover;
        private String coverTag;
        private int segId;

        @NoArgsConstructor
        @Data
        public static class SupplemetParamEntity {
            private String hp_moduletitle;
            private String coverID;
            private String liveOnlineNumber;
        }
    }

    @NoArgsConstructor
    @Data
    public static class SupplementParamToClientEntity {
        private String ops;
    }

    @NoArgsConstructor
    @Data
    public static class CloudMusicMyFollowRecInfoEntity {
    }
}

修改DiscoverFragment布局

修改DiscoverFragment

//第一步
private LookAdapter lookAdapter;
//第二步
lookAdapter = new LookAdapter(getContext());
        LinearLayoutManager managerLook = new LinearLayoutManager(getContext());
        managerLook.setOrientation(LinearLayoutManager.HORIZONTAL);
        binding.lookRecycle.setLayoutManager(managerLook);
        binding.lookRecycle.setHasFixedSize(true);
        binding.lookRecycle.setAdapter(lookAdapter);
//第三步添加数据
 private void initObserver() {

        viewModel.requireDiscover(false).observe(getViewLifecycleOwner(), homeDiscoverEntityApiResponse -> {
            if (homeDiscoverEntityApiResponse.getStatus() == Status.SUCCESS){
                for (HomeDiscoverEntity.DataEntity.BlocksEntity block : homeDiscoverEntityApiResponse.getData().getData().getBlocks()){
                    switch (block.getBlockCode()){
                        case "HOMEPAGE_BANNER": //banner
                            String bannerJson = new Gson().toJson(block.getExtInfo());
                            viewModel.bannerList = new Gson().fromJson(bannerJson,BannerExtInfoEntity.class);
                            break;
                        case "HOMEPAGE_BLOCK_PLAYLIST_RCMD": //推荐歌单
                            viewModel.recommendList = block.getCreatives();
                            break;
                        case "HOMEPAGE_BLOCK_LISTEN_LIVE"://直播
                            binding.tvLook.setText(block.getUiElement().getSubTitle().getTitle());
                            binding.tvLookMore.setText(block.getUiElement().getButton().getText());
                            String lookJson = new Gson().toJson(block.getExtInfo());
                            viewModel.lookLiveList = new Gson().fromJson(lookJson,new TypeToken<List<LookLiveEntity>>(){}.getType());
                            break;
                        case "HOMEPAGE_BLOCK_MGC_PLAYLIST"://雷达歌单
                            viewModel.selfMgcList = block.getCreatives();
                            binding.tvMgc.setText(block.getUiElement().getSubTitle().getTitle());
                            binding.tvMgcMore.setText(block.getUiElement().getButton().getText());
                            break;

                    }
                    binding.tvBottom.setText(homeDiscoverEntityApiResponse.getData().getData().getPageConfig().getNodataToast());
                }
                initData(viewModel.bannerList.getBanners());
                adapter.setDataList(viewModel.recommendList);
                mgcAdapter.setDataList(viewModel.selfMgcList);
                lookAdapter.setDataList(viewModel.lookLiveList);
            }else {
                Log.e("报错",homeDiscoverEntityApiResponse.getMessage());
            }
        });
    }

修改DiscoverFragmentViewModel

public class DiscoverFragmentViewModel extends ViewModel {

    public String date = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "";

    public BannerExtInfoEntity bannerList;

    public List<HomeDiscoverEntity.DataEntity.BlocksEntity.CreativesEntity> recommendList;

    public List<HomeDiscoverEntity.DataEntity.BlocksEntity.CreativesEntity> selfMgcList;

    public List<LookLiveEntity>  lookLiveList;


    public LiveData<ApiResponse<HomeDiscoverEntity>> requireDiscover(Boolean refresh){
        return RetrofitUtils.getmApiUrl().requireHomeDiscover(refresh);
    }


}

新增本地html(vip.html)

新增文件assets/web/vip.html:

<html style="height: 100%;">
<head>
    <meta name="viewport" content="width=device-width, user-scalable=no"><title>75352cbecbf8939e377cf67342546dda.png (135×51)</title>
</head>
<body style="margin: 0px; background: #00000000; height: 100%">
<img style="display: block;-webkit-user-select: none;max-width: 100%;margin: auto;" src="https://p5.music.126.net/obj/wo3DlcOGw6DClTvDisK1/4417174746/b7e0/c76d/01b9/75352cbecbf8939e377cf67342546dda.png">
</body>
</html>

对应网页vip效果如下:
vip效果图

引用三方lib

//加载网页
implementation 'com.github.Tobeyr1:webLoading:1.0.1'
//Jsoup
    implementation 'org.jsoup:jsoup:1.13.1'

修改fragment_mine.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="vm"
            type="com.tobery.personalmusic.ui.home.MainViewModel" />
    </data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grays_10">


    <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"
        />

    <View
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_0"
        android:layout_marginTop="@dimen/dp_40"
        android:background="@drawable/bg_view_white_full"
        android:paddingBottom="@dimen/dp_24"
        app:layout_constraintTop_toTopOf="@id/img_head"
        app:layout_constraintBottom_toBottomOf="@id/tv_follow"
        android:padding="@dimen/dp_24"
        android:layout_marginStart="@dimen/dp_8"
        android:layout_marginEnd="@dimen/dp_8"
        />

    <ImageView
        android:id="@+id/img_head"
        android:layout_width="@dimen/dp_80"
        android:layout_height="@dimen/dp_80"
        imSrc="@{vm.ui.imageUrl}"
        error="@{@drawable/ic_banner_loading}"
        android:layout_margin="@dimen/dp_16"
        android:elevation="@dimen/dp_8"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/view_title_bg"
        />

    <WebView
        android:id="@+id/web_vip"
        android:layout_width="@dimen/dp_40"
        android:layout_height="@dimen/dp_20"
        app:layout_constraintBottom_toBottomOf="@id/tv_nickname"
        app:layout_constraintStart_toEndOf="@id/tv_nickname"
        android:layout_marginStart="@dimen/dp_5"
        />

    <TextView
        android:id="@+id/tv_nickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{vm.ui.nickname}"
        android:textColor="@color/black"
        android:textSize="@dimen/sp_18"
        android:textStyle="bold"
        app:layout_constraintTop_toBottomOf="@id/img_head"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />

    <TextView
        android:id="@+id/tv_follow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{vm.ui.follows}"
        android:textColor="@color/grays_06"
        android:layout_marginTop="@dimen/dp_50"
        app:layout_constraintTop_toBottomOf="@id/img_head"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

新增UserInfoUi

public class UserInfoUi implements Serializable {

    public ObservableField<String> imageUrl;
    public ObservableField<String> nickname;//昵称
    public ObservableInt userId;
    public ObservableField<String> signature;//个签
    public ObservableField<String> follows;//关注
    public ObservableField<String> followeds;//粉丝

    public UserInfoUi(ObservableField<String> imageUrl, ObservableField<String> nickname, ObservableInt userId,ObservableField<String> signature, ObservableField<String> follows, ObservableField<String> followeds) {
        this.nickname = nickname;
        this.imageUrl = imageUrl;
        this.userId = userId;
        this.signature = signature;
        this.follows = follows;
        this.followeds = followeds;
    }
}

修改MainViewModel

public class MainViewModel extends ViewModel {

    private SavedStateHandle state;

    public UserInfoUi ui;

    private String userInfo;

    public MainViewModel(SavedStateHandle savedStateHandle) {
        this.state = savedStateHandle;
        ui = state.get(KEY_MAIN_UI) == null ? new UserInfoUi(new ObservableField<>(""), new ObservableField<>(""), new ObservableInt(0), new ObservableField<>(""), new ObservableField<>(""), new ObservableField<>("")) : state.get(KEY_MAIN_UI);
    }

    public void initUi() {
        userInfo = SharePreferencesUtil.getInstance(ContextProvider.get().getContext())
                .getUserInfo();
        LoginEntity data = new Gson().fromJson(userInfo, LoginEntity.class);
        if (null != data.getProfile()) {
            ui.nickname.set(data.getProfile().getNickname());
            ui.imageUrl.set(data.getProfile().getAvatarUrl());
            ui.userId.set(data.getProfile().getUserId());
            ui.signature.set(data.getProfile().getSignature());
            ui.follows.set(data.getProfile().getFollows()+"关注");
            ui.followeds.set(data.getProfile().getFolloweds()+"粉丝");
        }
    }
}

新增MineFragmentViewModel(我的页面的viewmodel)

public class MineFragmentViewModel extends ViewModel {

    public LiveData<ApiResponse<VipInfoEntity>> getVipInfo(){
        return RetrofitUtils.getmApiUrl().getVipInfo();
    }
}

新增vip信息实体类

@NoArgsConstructor
@Data
public class VipInfoEntity {

    private String message;
    private DataEntity data;
    private int code;

    @NoArgsConstructor
    @Data
    public static class DataEntity {
        private String redVipLevelIcon;
        private int redVipLevel;
        private int redVipAnnualCount;
        private MusicPackageEntity musicPackage;
        private AssociatorEntity associator;
        private String redVipDynamicIconUrl;
        private String redVipDynamicIconUrl2;

        @NoArgsConstructor
        @Data
        public static class MusicPackageEntity {
            private int vipCode;
            private long expireTime;
            private boolean isSignDeduct;
            private boolean isSign;
            private boolean isSignIapDeduct;
            private boolean isSignIap;
        }

        @NoArgsConstructor
        @Data
        public static class AssociatorEntity {
            private int vipCode;
            private long expireTime;
            private boolean isSignDeduct;
            private boolean isSign;
            private boolean isSignIapDeduct;
            private boolean isSignIap;
        }
    }
}

新增请求vip接口

@GET("vip/info")//vip信息
    LiveData<ApiResponse<VipInfoEntity>> getVipInfo();

新增MineFragment

public class MineFragment extends Fragment {

    private FragmentMineBinding binding;

    private MainViewModel homeViewModel;

    private MineFragmentViewModel viewModel;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = FragmentMineBinding.inflate(inflater);
        homeViewModel = new ViewModelProvider(this).get(MainViewModel.class);
        viewModel = new ViewModelProvider(this).get(MineFragmentViewModel.class);
        binding.setLifecycleOwner(this);
        binding.setVm(homeViewModel);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        homeViewModel.initUi();
        initWebView();
        initObserver();
    }

    @SuppressLint("SetJavaScriptEnabled")
    private void initWebView() {
        binding.webVip.getSettings().setJavaScriptEnabled(true);
    }

    private void initObserver() {

        viewModel.getVipInfo().observe(getViewLifecycleOwner(), vipInfoEntityApiResponse -> {
            if (vipInfoEntityApiResponse.getStatus() == Status.SUCCESS){
                binding.webVip.loadDataWithBaseURL(null,changeImageUrl(vipInfoEntityApiResponse.getData().getData().getRedVipDynamicIconUrl2()),"text/html", "utf-8", null);
            }
        });
    }

    private String changeImageUrl(String url) {
        Document doc = null;
        try {
            InputStream file = getResources().getAssets().open("web/vip.html");
            doc = Jsoup.parse(file, "UTF-8", url);
            Elements pngs = doc.select("img[src$=.png]");
            pngs.attr("src",url);
            file.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert doc != null;
        return doc.toString();
    }
}

  到此文章结束,有问题欢迎批评指正,觉得不错的也请点个赞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪の星空朝酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值