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

news2024/11/15 9:21:49

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

实现效果如下:

1.主函数代码:

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();

    }
}

主函数布局:

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

实体类:

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;
    }
}
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;
    }
}

适配器:

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);
    }

}
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选择背景: 

<?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>
<?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>

颜色:

<?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>

适配器布局:

<?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:

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")
}

清单文件:

<?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.图片如下:

项目源码:点击下载源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1387766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pycharm管理仓库(Manager Repository)不见了

经常使用pycharm的大佬们都知道&#xff0c;pycharm中内置了很多库和包&#xff0c;很好用 但是下载来用自带的源很麻烦&#xff0c;于是就用国内的源 可以当我们添加管理仓库的时候&#xff0c;却没有了按钮&#xff0c;如何解决呢&#xff1f; 回到pycharm的主界面&#xf…

C语言:自定义类型——结构体

一、什么叫做结构体 C语⾔已经提供了内置类型&#xff0c;如&#xff1a;char、short、int、long、float、double等&#xff0c;但是只有这些内置类型还是不够的&#xff0c;假设我想描述学⽣&#xff0c;描述⼀本书&#xff0c;这时单⼀的内置类型是不⾏的。描述⼀个学⽣需要 …

Leetcode2707. 字符串中的额外字符

Every day a Leetcode 题目来源&#xff1a;2707. 字符串中的额外字符 解法1&#xff1a;动态规划 题目要求将字符串 s 分割成若干个互不重叠的子字符串&#xff08;以下简称为子串&#xff09;&#xff0c;同时要求每个子串都必须在 dictionary 中出现。一些额外的字符可能…

【EI会议征稿通知】第五届计算机通信与网络安全国际学术会议 (CCNS 2024)

第五届计算机通信与网络安全国际学术会议 (CCNS 2024) 2024 5th International Conference on Computer Communication and Network Securit IEEE Fellow、海内外高层次专家云集&#xff0c;EI、Scopus稳定检索 第五届计算机通信与网络安全国际学术会议 (CCNS 2024) 将于202…

立白科技集团:研发安全推动数字化蜕变,日化业务再上新高度

立白科技集团成立于1994年&#xff0c;是我国日化行业的领军企业&#xff0c;致力于成为一家“品牌引领、数字经营、富有创新、富有活力”的智慧服务型企业。从2018年开始&#xff0c;立白科技集团加速数字化转型&#xff0c;打造数据和业务中台&#xff0c;并建立toB和toC平台…

仿真验证方法(1)——动态验证

一、概述 1.1 验证的目的和方法 在现代集成电路设计中&#xff0c;验证所占工作量超过70%。验证要求真实而完备&#xff0c;它决定了设计的成败与成本。 验证的目的 原始描述是否正确&#xff1f;&#xff08;代码&#xff09; 逻辑功能是否正确&#xff1f;&#xff08;功能…

vue中使用mpegts.js播放flv的直播视频流

第一步&#xff1a;引入mpegts.js npm install --save mpegts.js 第二步&#xff1a;在vue文件中引入mpegts.js的依赖 第三步&#xff1a;编写展示视频的盒子 我这里是使用循环遍历的方式创建video标签&#xff0c;这样方便后面随机展示视频使用 <template><div>&l…

【前端发版】vue前端发版 步骤

1、 提交代码 代码合并通过之后到deb分支 2、git checkout 切换到dev分支上 运行起来看看自己刚刚提交的代码有没有错误 3、拉取最新代码 git pull 3、yarn run build 4、打包好的文件叫dist 重新命名为服务器里替换包名 5、登录文件传输 开始替换 替换的过程中 首先删除备…

五指CMS copyfrom.php SQL注入漏洞复现(CVE-2023-52064)

0x01 产品简介 WUZHI CMS是北京五指互联科技有限公司 的一套基于PHP和MySQL的开源内容管理系统,响应式布局,一个网站兼容多个终端 微信接口全支持,快速构建微营销平台 开放接口,支持第三方APP无缝接入。 0x02 漏洞概述 Wuzhicms 内容管理系统的/core/admin/copyfrom.p…

Python入门-字面量,函数,类

Python 中常用的有6种值&#xff08;数据&#xff09;的类型 (1)字符串需要用英文的双引号包围起来&#xff0c;比如打印"helloworld" &#xff08;2&#xff09;浮点数&#xff0c;整数&#xff0c;字符串等字面量的写法 &#xff08;3&#xff09;字符串定义及打印…

系统架构09 - 信息安全(中)

信息安全 信息摘要特点算法作用 数字签名主要功能原理 数字证书&#xff08;公钥证书&#xff09;原理格式 PKI公钥基础设施组成部分基础技术功能 信息摘要 就是一段数据的特征信息。 当数据发生了改变&#xff0c;信息摘要也会发生改变。 发送方会将数据和信息摘要一起传给接…

二叉树:从基础结构到高级遍历技术

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 引言结构定义接口需求构建二叉树销毁二叉树计算节点和叶子的数量二叉树节点个数二叉树叶子节点个数二叉树第k层节点个数 二叉树查找值为x的节点二叉树的…

Dhcp中继华为+虚拟机

拓扑图&#xff1a; 配置二层交换机sw1 创建vlan 将e0/0/1接口封装到vlan10 将e0/0/2接口封装到vlan20 将e0/0/4接口封装到vlan100 将e0/0/3接口配置为中继口 并允许所有vlan通过 配置三层交换机Lsw1 将e0/0/1接口配置中继口 并允许所有vlan通过 开启dhcp 创建vlan 10 20 100 进…

前端学习路径

菜鸟感觉很多人不太知道菜鸟写的博客是一个可以跟着学习、一起深入理解的过程&#xff0c;其中包括了菜鸟从刚开始学习到后面重新学习&#xff0c;再到后面进入学框架等一系列学习过程、知识和感悟&#xff0c;所以菜鸟把自己的博客整理成一个目录提取出来&#xff0c;好让读者…

使用vue快速开发一个带弹窗的Chrome插件

vue-chrome-extension-quickstart 说在前面 &#x1f388;平时我们使用Chrome插件通常都只是用来编写简单的js注入脚本&#xff0c;大家有没有遇到过需要插件在页面上注入一个弹窗呢&#xff1f;比如我们希望可以通过快捷键快速唤起ChatGPT面板或者快速唤起一个翻译面板&#x…

汽车线束的汽配企业MES管理系统解决方案

随着科技的飞速发展和环保需求的日益提升&#xff0c;新能源汽车在全球范围内崭露头角&#xff0c;成为未来出行的主导力量。在这股浪潮中&#xff0c;中国凭借其强大的研发实力和市场敏锐度&#xff0c;迅速崛起为新能源汽车领域的佼佼者。而作为汽车数字化控制与智能化应用的…

openpyxl绘制图表

嘿&#xff0c;你是不是在处理Excel文件时感到束手无策&#xff1f;是不是想要一个简单而又强大的工具来处理数据分析和图表制作&#xff1f;别担心&#xff0c;我们有解决方案&#xff01;让我向你介绍openpyxl&#xff0c;这是一个Python库&#xff0c;专门用于处理Excel文件…

从车联网到智慧城市:智慧交通的革新之路

一、引言 1、智慧城市的概念和发展背景 智慧城市&#xff08;Smart City&#xff09;是指以信息技术为基础&#xff0c;运用信息与通信等手段&#xff0c;对城市各个核心系统各项关键数据进行感测、分析、整合和利用&#xff0c;实现对城市生活环境的感知、资源的调控&#x…

基于Ubuntu22.04部署生产级K8S集群v1.27(规划和核心组件部署篇)

本文档主要根据k8s官网文档和其插件的官网文档&#xff0c;参考部分他人优秀经验&#xff0c;在实际操作中逐渐完成&#xff0c;比较详尽&#xff0c;适合在境内学习者和实践者参考。 实操环境基于VMware Workstation 17 pro&#xff0c;采用ubuntu22.04操作系统&#xff08;有…

MATLAB运行simulink模型显示找不到库Failed to load library

MATLAB运行simulink模型显示找不到库Failed to load library ‘ 原因 上述的错误即提示加载某一个库失败了&#xff0c;原因就是MATLAB需要在其设定的set path中寻找。 设置 paths 查看paths 添加成功后再次打开MATLAB的set path&#xff0c;可以看到相关文件及库被添加进来…