Android 仿快手视频列表,RecyclerView与Banner联动效果

这是看到群里讨论过快手APP的一个观看他人视频列表的一个联动效果,但是并不是完全按照这个软件的效果来做的,只是参考,并不是完全仿照这个软件来做的,没时间去优化排版问题了,请见谅,如图:

实现效果如下:

1.主函数代码:

java 复制代码
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.example.mytestapplication.R;
import com.example.mytestapplication.adapter.ImageAdapter;
import com.example.mytestapplication.bean.DataBean;
import com.example.mytestapplication.bean.SelectBean;
import com.example.mytestapplication.databinding.ActivityYouthBannerBinding;
import com.example.mytestapplication.pbl.FullyStaggeredGridLayoutManager;
import com.example.mytestapplication.recycler.BannerScreenAdapter;
import com.example.mytestapplication.recycler.ScreenAllAdapter;
import com.google.android.material.snackbar.Snackbar;
import com.youth.banner.indicator.CircleIndicator;
import com.youth.banner.listener.OnBannerListener;
import com.youth.banner.listener.OnPageChangeListener;

import java.util.ArrayList;
import java.util.List;

/**
 * https://github.com/youth5201314/banner
 *
 * https://blog.csdn.net/u014628886/article/details/52074383
 *
 * https://blog.csdn.net/itTalmud/article/details/130330097
 */
public class YouthBannerActivity extends AppCompatActivity {

    private ActivityYouthBannerBinding binding;
    private FullyStaggeredGridLayoutManager slm = null;
    private List<Integer> picList;
    private ImageAdapter adapter;
    private Integer[] mImgIds = {R.drawable.image7, R.drawable.image8, R.drawable.image9, R.drawable.image10, R.drawable.image11};
    private BannerScreenAdapter mBannerScreenAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_youth_banner, null, false);
        setContentView(binding.getRoot());

        binding.btTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                binding.banner.setCurrentItem(2);
                binding.banner.stop();
            }
        });
        initData();

    }

    private void initData() {

        // 轮播的图片集合
        picList = new ArrayList<>();

        picList.add(R.mipmap.aa);
        picList.add(R.mipmap.ab);
        picList.add(R.mipmap.ac);
        picList.add(R.mipmap.mm);
        picList.add(R.mipmap.aa);
        picList.add(R.mipmap.ab);
        picList.add(R.mipmap.ac);
        picList.add(R.mipmap.mm);
        picList.add(R.mipmap.aa);
        picList.add(R.mipmap.ab);
        picList.add(R.mipmap.ac);
        picList.add(R.mipmap.mm);

        //模拟数据源
        ArrayList imgLists = new ArrayList<>();
        for (int i = 0; i < mImgIds.length; i++) {
            imgLists.add(mImgIds[i]);
        }

        List<SelectBean> selectBeans = SelectBean.getTestData();

        List<DataBean> datas =  DataBean.getTestData2();

        //自定义的图片适配器,也可以使用默认的BannerImageAdapter
        adapter = new ImageAdapter(datas);

        binding.banner.setAdapter(adapter)
//              .setCurrentItem(0,false)
                //添加生命周期观察者
                .addBannerLifecycleObserver(this)
                //设置指示器
                .setIndicator(new CircleIndicator(this))
                .setOnBannerListener((data, position) -> {
//                    Snackbar.make(binding.banner, ((DataBean) data).title, Snackbar.LENGTH_SHORT).show();
//                    LogUtils.d("position:" + position);
                });

        //添加item之间切换时的间距(如果使用了画廊效果就不要添加间距了,因为内部已经添加过了)
//        banner.addPageTransformer(new MarginPageTransformer( BannerUtils.dp2px(10)));

        //Banner点击事件
        binding.banner.setOnBannerListener(new OnBannerListener() {
            @Override
            public void OnBannerClick(Object data, int position) {
                //点击Banner,关联对应的RecyclerView数据
                binding.rvScreen.scrollToPosition(position);
                mBannerScreenAdapter.setPosition(position);
                mBannerScreenAdapter.notifyDataSetChanged();
            }
        });

//        binding.banner.setOnScrollChangeListener(new View.OnScrollChangeListener() {
//            @Override
//            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//
//            }
//        });
        //Banner滑动监听事件
        binding.banner.addOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                //点击Banner,关联对应的RecyclerView数据
                binding.rvScreen.scrollToPosition(position);
                mBannerScreenAdapter.setPosition(position);
                mBannerScreenAdapter.notifyDataSetChanged();
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });


        mBannerScreenAdapter = new BannerScreenAdapter(this, selectBeans);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        binding.rvScreen.setLayoutManager(layoutManager);
        binding.rvScreen.setAdapter(mBannerScreenAdapter);

        mBannerScreenAdapter.setOnItemClickListener(new BannerScreenAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                binding.banner.setCurrentItem(position+1);
                binding.banner.stop();
            }
        });
    }

    @Override
    protected void onStop() {
        super.onStop();

    }

    @Override
    protected void onResume() {
        super.onResume();


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

    }
}

主函数布局:

html 复制代码
<layout 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">

    <data>

    </data>

    <RelativeLayout xmlns:banner="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.youth.banner.Banner
            android:id="@+id/banner"
            android:layout_width="280dp"
            android:layout_height="180dp"
            android:layout_margin="10dp"
            banner:banner_indicator_normal_color="@android:color/white"
            banner:banner_indicator_selected_color="@color/purple_500"
            banner:banner_radius="5dp" />

        <com.youth.banner.indicator.RoundLinesIndicator
            android:id="@+id/indicator"
            android:layout_width="300dp"
            android:layout_height="20dp"
            android:layout_below="@+id/banner"
            android:layout_centerHorizontal="true"
            android:visibility="gone" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rvScreen"
            android:layout_margin="10dp"
            android:layout_width="100dp"
            android:layout_height="180dp"
            android:layout_alignParentRight="true"/>

        <Button
            android:id="@+id/btTest"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="刷新"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="20dp" />
    </RelativeLayout>
</layout>

实体类:

java 复制代码
import com.example.mytestapplication.R;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class SelectBean implements Serializable {
    public Integer imageRes;

    public Integer getImageRes() {
        return imageRes;
    }

    public void setImageRes(Integer imageRes) {
        this.imageRes = imageRes;
    }

    public boolean isSelect() {
        return isSelect;
    }

    public void setSelect(boolean select) {
        isSelect = select;
    }

    public boolean isSelect;

    public SelectBean(Integer imageRes, boolean isSelect) {
        this.imageRes = imageRes;
        this.isSelect = isSelect;
    }

//    public SelectBean(String imageUrl, String title, int viewType) {
//        this.imageUrl = imageUrl;
//        this.title = title;
//        this.viewType = viewType;
//    }

    public static List<SelectBean> getTestData() {
        List<SelectBean> list = new ArrayList<>();
        list.add(new SelectBean(R.drawable.image7, false));
        list.add(new SelectBean(R.drawable.image8, false));
        list.add(new SelectBean(R.drawable.image9, false));
        list.add(new SelectBean(R.drawable.image10, false));
        list.add(new SelectBean(R.drawable.image11, false));
        return list;
    }

    public static List<String> getColors(int size) {
        List<String> list = new ArrayList<>();
        for(int i = 0; i < size; i++) {
            list.add(getRandColor());
        }
        return list;
    }

    /**
     * 获取十六进制的颜色代码.例如  "#5A6677"
     * 分别取R、G、B的随机值,然后加起来即可
     *
     * @return String
     */
    public static String getRandColor() {
        String R, G, B;
        Random random = new Random();
        R = Integer.toHexString(random.nextInt(256)).toUpperCase();
        G = Integer.toHexString(random.nextInt(256)).toUpperCase();
        B = Integer.toHexString(random.nextInt(256)).toUpperCase();

        R = R.length() == 1 ? "0" + R : R;
        G = G.length() == 1 ? "0" + G : G;
        B = B.length() == 1 ? "0" + B : B;

        return "#" + R + G + B;
    }
}
java 复制代码
import com.example.mytestapplication.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class DataBean {
    public Integer imageRes;
    public String imageUrl;
    public String title;
    public int viewType;

    public DataBean(Integer imageRes, String title, int viewType) {
        this.imageRes = imageRes;
        this.title = title;
        this.viewType = viewType;
    }

    public DataBean(String imageUrl, String title, int viewType) {
        this.imageUrl = imageUrl;
        this.title = title;
        this.viewType = viewType;
    }

    public static List<DataBean> getTestData() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean(R.drawable.image1, "相信自己,你努力的样子真的很美", 1));
        list.add(new DataBean(R.drawable.image2, "极致简约,梦幻小屋", 3));
        list.add(new DataBean(R.drawable.image3, "超级卖梦人", 3));
        list.add(new DataBean(R.drawable.image4, "夏季新搭配", 1));
        list.add(new DataBean(R.drawable.image5, "绝美风格搭配", 1));
        list.add(new DataBean(R.drawable.image6, "微微一笑 很倾城", 3));
        return list;
    }

    public static List<DataBean> getTestData2() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean(R.drawable.image7, "听风.赏雨", 3));
        list.add(new DataBean(R.drawable.image8, "迪丽热巴.迪力木拉提", 1));
        list.add(new DataBean(R.drawable.image9, "爱美.人间有之", 3));
        list.add(new DataBean(R.drawable.image10, "洋洋洋.气质篇", 1));
        list.add(new DataBean(R.drawable.image11, "生活的态度", 3));
        return list;
    }

    /**
     * 仿淘宝商品详情第一个是视频
     * @return
     */
    public static List<DataBean> getTestDataVideo() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/09/mp4/190309153658147087.mp4", "第一个放视频", 2));
        list.add(new DataBean(R.drawable.image7, "听风.赏雨", 1));
        list.add(new DataBean(R.drawable.image8, "迪丽热巴.迪力木拉提", 1));
        list.add(new DataBean(R.drawable.image9, "爱美.人间有之", 1));
        list.add(new DataBean(R.drawable.image10, "洋洋洋.气质篇", 1));
        list.add(new DataBean(R.drawable.image11, "生活的态度", 1));
        return list;
    }

    public static List<DataBean> getTestData3() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("https://img.zcool.cn/community/013de756fb63036ac7257948747896.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01639a56fb62ff6ac725794891960d.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01270156fb62fd6ac72579485aa893.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/01233056fb62fe32f875a9447400e1.jpg", null, 1));
        list.add(new DataBean("https://img.zcool.cn/community/016a2256fb63006ac7257948f83349.jpg", null, 1));
        return list;
    }

    public static List<DataBean> getVideos() {
        List<DataBean> list = new ArrayList<>();
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/18/mp4/190318231014076505.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/18/mp4/190318214226685784.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/19/mp4/190319125415785691.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/14/mp4/190314223540373995.mp4", null, 0));
        list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/14/mp4/190314102306987969.mp4", null, 0));
        return list;
    }


    public static List<String> getColors(int size) {
        List<String> list = new ArrayList<>();
        for(int i = 0; i < size; i++) {
            list.add(getRandColor());
        }
        return list;
    }

    /**
     * 获取十六进制的颜色代码.例如  "#5A6677"
     * 分别取R、G、B的随机值,然后加起来即可
     *
     * @return String
     */
    public static String getRandColor() {
        String R, G, B;
        Random random = new Random();
        R = Integer.toHexString(random.nextInt(256)).toUpperCase();
        G = Integer.toHexString(random.nextInt(256)).toUpperCase();
        B = Integer.toHexString(random.nextInt(256)).toUpperCase();

        R = R.length() == 1 ? "0" + R : R;
        G = G.length() == 1 ? "0" + G : G;
        B = B.length() == 1 ? "0" + B : B;

        return "#" + R + G + B;
    }
}

适配器:

java 复制代码
import android.view.ViewGroup;
import android.widget.ImageView;

import com.example.mytestapplication.bean.DataBean;
import com.example.mytestapplication.viewholder.ImageHolder;
import com.youth.banner.adapter.BannerAdapter;

import java.util.List;


/**
 * 自定义布局,图片
 */
public class ImageAdapter extends BannerAdapter<DataBean, ImageHolder> {

    public ImageAdapter(List<DataBean> mDatas) {
        //设置数据,也可以调用banner提供的方法,或者自己在adapter中实现
        super(mDatas);
    }

    //更新数据
    public void updateData(List<DataBean> data) {
        //这里的代码自己发挥,比如如下的写法等等
        mDatas.clear();
        mDatas.addAll(data);
        notifyDataSetChanged();
    }


    //创建ViewHolder,可以用viewType这个字段来区分不同的ViewHolder
    @Override
    public ImageHolder onCreateHolder(ViewGroup parent, int viewType) {
        ImageView imageView = new ImageView(parent.getContext());
        //注意,必须设置为match_parent,这个是viewpager2强制要求的
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        imageView.setLayoutParams(params);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new ImageHolder(imageView);
    }

    @Override
    public void onBindView(ImageHolder holder, DataBean data, int position, int size) {
        holder.imageView.setImageResource(data.imageRes);
    }

}
java 复制代码
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.recyclerview.widget.RecyclerView;

import com.example.mytestapplication.R;
import com.example.mytestapplication.bean.SelectBean;

import java.util.List;

/**
 * https://www.itguest.com/post/aeijeb1a1.html
 * @date 2020/12/10
 * desc
 */
public class BannerScreenAdapter extends RecyclerView.Adapter<BannerScreenAdapter.ViewHolder> {

    private Context context;
    private List<Integer> mDataList;
    private List<SelectBean> mSelectBeanList;
    private OnItemClickListener onItemClickListener;
    private int mPosition = -1;
    private int currentPosition;
    private boolean isClick;
    private LinearLayout llView;

//    public BannerScreenAdapter(Context context, List<Integer> dataList) {
//        this.context = context;
//        this.mDataList = dataList;
//    }

    public BannerScreenAdapter(Context context, List<SelectBean> dataList) {
        this.context = context;
        this.mSelectBeanList = dataList;
    }

    @Override
    public int getItemCount() {
//        return Integer.MAX_VALUE;
        return mSelectBeanList.size();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view = LayoutInflater.from(context).inflate(R.layout.item_banner_screen, parent, false);
        final ViewHolder vh = new ViewHolder(view);
        int adapterPosition = vh.getAdapterPosition();
        int position = vh.getPosition();

//        boolean isSelect = mSelectBeanList.get(position).isSelect;
//        if(isSelect){
//            llView.setBackgroundResource(R.drawable.shape_bg_blue);
//        }else {
//            llView.setBackgroundResource(R.drawable.tab_bg);
//        }

//        view.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                int adapterPosition = vh.getAdapterPosition();
//                int position = vh.getPosition();
                for (int i = 0; i < mSelectBeanList.size(); i++) {
                    if(adapterPosition == i){
                        mSelectBeanList.get(vh.getPosition()).setSelect(true);
                        setCurrentPosition(vh.getAdapterPosition(), true);
                    }else {
                        mSelectBeanList.get(vh.getPosition()).setSelect(false);
                        setCurrentPosition(vh.getAdapterPosition(), false);
                    }
                }
//                if(!isClick){
//                    //调用setCurrentPosition()方法
//                    setCurrentPosition(vh.getAdapterPosition(),true);//记录并设为true
//                }else {
//                    //当某项点击状态为true 点击的时候判断当前位置和getAbsoluteAdapterPosition()为点击更新后适配器的位置是否一致?不一致说明点击了新的选项,记录isClick为false 更新新的位置。
//                    setCurrentPosition(vh.getAdapterPosition(), //记录当前点击
//                            getCurrentPosition()!=vh.getAdapterPosition());
//                }
//
//                notifyDataSetChanged();
//                onItemClickListener.onItemClick(vh.getPosition());
                notifyItemChanged(position);
//            }
//        });
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, @SuppressLint("RecyclerView") int position) {
//        int newPos = position % mDataList.size();
        int newPos = position % mSelectBeanList.size();
        holder.mDisplay.setImageResource(mSelectBeanList.get(newPos).getImageRes());
        holder.itemView.setTag(position);
        holder.mLlView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPosition = position;
//                mSelectBeanList.get(position).setSelect(true);
                notifyDataSetChanged();
                onItemClickListener.onItemClick(position);
            }
        });
        boolean isSelect = mSelectBeanList.get(getCurrentPosition()).isSelect;
//        if(getCurrentPosition() == position && isSelect){
        if(mPosition == position){
//            holder.mLlView.setBackgroundResource(R.drawable.shape_bg_blue);
            //单选:设置选择的背景
            holder.mLlView.setBackgroundResource(R.drawable.tab_bg);
            //选中后设置缩放动画:将图片放大一些
            ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f,1.1f);
            valueAnimator.setDuration(500);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //获取动画属性值
                    float value = (float) animation.getAnimatedValue();
                    holder.mDisplay.setScaleX(value);
                    holder.mDisplay.setScaleY(value);
                }
            });
            valueAnimator.start();
        }else {
            holder.mLlView.setBackgroundResource(R.drawable.shape_transparent_bg);
        }
    }


    class ViewHolder extends RecyclerView.ViewHolder {
        ImageView mDisplay;
        LinearLayout mLlView;

        public ViewHolder(View itemView) {
            super(itemView);
            mDisplay = itemView.findViewById(R.id.iv_display);
            mLlView = itemView.findViewById(R.id.ll_view);
        }
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.onItemClickListener = listener;
    }

    public interface OnItemClickListener {
        void onItemClick(int position);
    }

    //创建getCurrentPosition 返回当前位置
    private int getCurrentPosition() {
        return currentPosition;
    }
    //创建setCurrentPosition方法 记录当前点击选项和点击状态
    public void setCurrentPosition(int currentPosition,boolean isClick){
        this.currentPosition=currentPosition;
        this.isClick=isClick;
    }

    public void setPosition(int position){
        this.mPosition = position;
    }
}

shape选择背景:

html 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:gravity="center">
        <shape>
            <!-- 设置圆角 -->
            <corners android:radius="5dp" />
            <!-- 设置边框 -->
            <stroke
                android:width="1dp"
                android:color="@color/transparent" />
        </shape>
    </item>
</layer-list>
html 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:gravity="center">
        <shape>
            <!-- 设置圆角 -->
            <corners android:radius="5dp" />
            <!-- 设置边框 -->
            <stroke
                android:width="1dp"
                android:color="@color/teal_700" />
        </shape>
    </item>
</layer-list>

颜色:

html 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="grey_666">#666666</color>
    <color name="transparent">#00000000</color>
</resources>

适配器布局:

html 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="80dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:id="@+id/ll_view"
    android:gravity="center"
    android:background="@color/white"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_display"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="1dp"
        tools:src="@mipmap/ic_launcher" />

</LinearLayout>

依赖文件build.gradle.kts:

java 复制代码
plugins {
    id("com.android.application")
}

android {
    namespace = "com.example.mytestapplication"
    compileSdk = 33

    dataBinding {
        enable = true
    }

    defaultConfig {
        applicationId = "com.example.mytestapplication"
        minSdk = 24
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    buildFeatures {
        viewBinding = true
    }
}

dependencies {

    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("com.google.android.material:material:1.8.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
    implementation("androidx.navigation:navigation-fragment:2.5.3")
    implementation("androidx.navigation:navigation-ui:2.5.3")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

    implementation ("com.github.bumptech.glide:glide:4.12.0")
    implementation ("androidx.palette:palette:1.0.0")
    implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
//    implementation ("com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22")

    implementation ("io.github.youth5201314:banner:2.2.1")
}

清单文件:

java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!--允许Glide监视连接状态,并在用户从断开连接到已连接网络的状态。-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyTestApplication"
        tools:targetApi="31">
        <activity
            android:name=".youth.YouthBannerActivity"
            android:exported="true"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2.图片如下:

项目源码:点击下载源码

相关推荐
三少爷的鞋12 分钟前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)4 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码6 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程9 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程10 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓11 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer