RecyclerView实现Banner无限轮播

AndroidX RecyclerView实践-手写卡片式布局 文章目录前言功能拆解代码实现准备工作添加依赖MOCK数据创建适配器卡片布局实现思路分析初始配置自定义LayoutManager手势滑动移除实现思路分析自定义ItemTouchHelper.SimpleCallback点击按钮卡片飞出动画实现思路分析按钮点击监听自定义SimpleItemAnimator尾声 前言 RecyclerView系列总结: 《AndroidX RecyclerView总结-测量布局》 《AndroidX RecyclerView总结-Recycler》 《AndroidX Recyc 阅读详情

实现原理:

 

在这里插入图片描述

      1到second last为实际数据,0跟last为banner自动填充的item,其中0中数据跟second last项数据相同,last跟1项数据相同。
      当banner滑动(或者手动滑动)到0时,banner静默滚动到second last处(因为0跟second last图片相同所以用户无感知);当banner滑动到last时,banner静默滚动到1处。
  
 

代码:

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

//TODO 根据自己引用的RecyclerView修改引用
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.RecyclerView;

import com.facebook.drawee.view.SimpleDraweeView;
import com.huawei.glass.R;

import org.jetbrains.annotations.NotNull;

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

/**
 * Created by weixing on 2017/6/30.
 */
public class RecyclerBanner extends FrameLayout {
    /**导航圆点类型*/
    public static final short NAV_DOT = 0;
    /**导航条类型*/
    public static final short NAV_BOTTOM_BAR = 1;
    /**导航数字类型*/
    public static final short NAV_NUMBER = 2;

    private RecyclerView mRecyclerView;
    /**导航条及点的父控件*/
    private LinearLayout mDotContainer;
    /**导航dot及bar的drawable*/
    private GradientDrawable defaultDrawable, selectedDrawable;

    /**导航类型*/
    private int mNavType = 0;
    /**导航条宽度*/
    private int mNavBarWidth;
    /**导航文本控件*/
    private TextView mNavNumber;
    /**导航控件底部边距*/
    private int navBottomMargin = 30;

    /**默认导航颜色及选中导航颜色*/
    private int defaultColor = 0x75ffffff, selectColor = 0xffFF6822;


    private RecyclerAdapter mAdapter;
    private OnPagerClickListener mPageClickListener;
    private List<BannerEntity> mData = new ArrayList<>();

    /**圆点大小*/
    private int mDotSize;
    /**手指触屏位置*/
    private int startX, startY;
    /**当前滚动位置*/
    private int currentIndex;
    /**是否滚动*/
    private boolean isPlaying;

    public interface OnPagerClickListener {

        void onClick(BannerEntity entity);
    }

    public static interface BannerEntity {
        String getUrl();
    }

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            currentIndex = currentIndex >= mData.size() - 1 ? 1 : ++currentIndex;
            if (currentIndex >= mData.size()) {
                currentIndex = currentIndex % mData.size();
            }

            mRecyclerView.smoothScrollToPosition(currentIndex);

            sendEmptyMessageDelayed(0, 3000);

        }
    };

    public RecyclerBanner(Context context) {
        this(context, null);
    }

    public RecyclerBanner(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RecyclerBanner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//        defaultDrawable = new GradientDrawable();
//        defaultDrawable.setSize(mDotSize, mDotSize);
//        defaultDrawable.setCornerRadius(mDotSize);
//        defaultDrawable.setColor(0xffffffff);
//        selectedDrawable = new GradientDrawable();
//        selectedDrawable.setSize(mDotSize, mDotSize);
//        selectedDrawable.setCornerRadius(mDotSize);
//        selectedDrawable.setColor(0xff0094ff);



        LayoutParams vpLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mDotContainer = new LinearLayout(context);
        mDotContainer.setOrientation(LinearLayout.HORIZONTAL);
        LayoutParams linearLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mDotContainer.setGravity(Gravity.CENTER);
        linearLayoutParams.setMargins(0, 0, 0, navBottomMargin);
        mDotContainer.setPadding(mDotSize * 2, mDotSize * 2, mDotSize * 2, mDotSize * 2);
        linearLayoutParams.gravity = Gravity.BOTTOM;

        mRecyclerView = new RecyclerView(context);
        new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
        mAdapter = new RecyclerAdapter();
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NotNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);


                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    if (touched) {
                        int first = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
                        int last = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
                        int current;
                        if (first == 0) {
                            current = (int) Math.round((first + last) / 2.0 - 0.1);
                        } else {
                            current = (int) Math.round((first + last) / 2.0);
                        }

                        if (current == (mData.size() - 1)) {
                            current = 1;
                            mRecyclerView.scrollToPosition(1);
                        } else if (current == 0) {
                            current = mData.size() - 2;
                            mRecyclerView.scrollToPosition(mData.size() - 2);
                        }

                        if (currentIndex != current) {
                            currentIndex = current;
                            changePoint();
                        }

                        touched = false;
                        return;
                    }

                    if (currentIndex == mData.size() - 1) {
                        mRecyclerView.scrollToPosition(1);
                        currentIndex = 1;
                    }
                    changePoint();
                }
            }
        });

        addView(mRecyclerView, vpLayoutParams);
        addView(mDotContainer, linearLayoutParams);


        mNavBarWidth = (getResources().getDisplayMetrics().widthPixels - 160) / (mData.size() == 0 ? 5 : mData.size());
        mDotSize = (int) (6 * context.getResources().getDisplayMetrics().density + 0.5f);
        setNavColor(defaultColor, selectColor);
        initNavView();
        /*
        TODO 为方便使用没有在属性xml文件中定义属性,如果要使用则直接调用类方法设置比例
        //初始化比例
        TypedArray a = getContext().obtainStyledAttributes(attrs,
                R.styleable.RatioImageView);
        mIsWidthFitDrawableSizeRatio = a.getBoolean(R.styleable.RatioImageView_is_width_fix_drawable_size_ratio,
                mIsWidthFitDrawableSizeRatio);
        mIsHeightFitDrawableSizeRatio = a.getBoolean(R.styleable.RatioImageView_is_height_fix_drawable_size_ratio,
                mIsHeightFitDrawableSizeRatio);
        mHeightRatio = a.getFloat(
                R.styleable.RatioImageView_height_to_width_ratio, mHeightRatio);
        mWidthRatio = a.getFloat(
                R.styleable.RatioImageView_width_to_height_ratio, mWidthRatio);
        a.recycle();*/
    }

    public void setOnPagerClickListener(OnPagerClickListener onPagerClickListener) {
        this.mPageClickListener = onPagerClickListener;
    }

    /**设置是否应该滚动*/
    public synchronized void setPlaying(boolean playing) {
        if (!isPlaying && playing && mAdapter != null && mAdapter.getItemCount() > 2) {
            mHandler.removeMessages(0);
            mHandler.sendEmptyMessageDelayed(0, 3000);
            isPlaying = true;
        } else if (isPlaying && !playing) {
            mHandler.removeMessages(0);
            isPlaying = false;
        }
    }

    /**
     * 设置data需在setColor及setNavType之后
     * @param datas 数据列表
     * @return 数据数量
     */
    public int setDatas(List<? extends BannerEntity> datas) {
        setPlaying(false);
        mDotContainer.removeAllViews();
        if (mData != null) {
            this.mData.clear();
        } else {
            this.mData = new ArrayList<>();
        }
        this.mData.addAll(datas);

        if (this.mData.size() > 1) {
            currentIndex = 1;//设置无限循环播放
            mAdapter.notifyDataSetChanged();
            mRecyclerView.scrollToPosition(currentIndex);
//            for (int i = 0; i < this.mData.size(); i++) {
//                ImageView img = new ImageView(getContext());
//                LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//                lp.leftMargin = mDotSize / 2;
//                lp.rightMargin = mDotSize / 2;
//                img.setImageDrawable(i == 0 ? selectedDrawable : defaultDrawable);
//                mDotContainer.addView(img, lp);
//            }

            if (mNavType != NAV_NUMBER) {
                for (int i = 0; i < this.mData.size(); i++) {
                    ImageView img = new ImageView(getContext());
                    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                    lp.leftMargin = mDotSize / 2;
                    lp.rightMargin = mDotSize / 2;
                    img.setImageDrawable(i == 0 ? selectedDrawable : defaultDrawable);
                    mDotContainer.addView(img, lp);
                }
            } else {
                mNavNumber.setText(String.format(Locale.CHINA, "1/%d", datas.size()));
            }

            setPlaying(true);

            mData.add(0, mData.get(mData.size() - 1));
            mData.add(mData.get(1));
        } else {
            currentIndex = 0;
            mAdapter.notifyDataSetChanged();
        }
        return this.mData.size();
    }

    private void initNavView() {
        initNavView(mNavType);
    }

    /**初始化导航类型*/
    private void initNavView(int type){
        if (type == NAV_DOT) {
            if (mDotContainer != null) {
                mDotContainer.setVisibility(VISIBLE);
            }
            if (mNavNumber != null && mNavNumber.getVisibility() == VISIBLE) {
                mNavNumber.setVisibility(GONE);
            }
            defaultDrawable = new GradientDrawable();
            defaultDrawable.setSize(mDotSize, mDotSize);
            defaultDrawable.setCornerRadius(mDotSize);
            defaultDrawable.setColor(defaultColor);
            selectedDrawable = new GradientDrawable();
            selectedDrawable.setSize(mDotSize, mDotSize);
            selectedDrawable.setCornerRadius(mDotSize);
            selectedDrawable.setColor(selectColor);
        } else if (type == NAV_BOTTOM_BAR) {
            if (mDotContainer != null) {
                mDotContainer.setVisibility(VISIBLE);
            }
            if (mNavNumber != null && mNavNumber.getVisibility() == VISIBLE) {
                mNavNumber.setVisibility(GONE);
            }

            defaultDrawable = new GradientDrawable();
            defaultDrawable.setSize(mNavBarWidth, mDotSize / 3);
            defaultDrawable.setCornerRadius(0);
            defaultDrawable.setColor(defaultColor);
            selectedDrawable = new GradientDrawable();
            selectedDrawable.setSize(mNavBarWidth, mDotSize / 3);
            selectedDrawable.setCornerRadius(0);
            selectedDrawable.setColor(selectColor);
        } else if (type == NAV_NUMBER) {
            if (mDotContainer != null) {
                mDotContainer.setVisibility(GONE);
                mDotContainer.removeAllViews();
            }
            if (mNavNumber != null) {
                mNavNumber.setVisibility(VISIBLE);
                return;
            }
            mNavNumber = new TextView(getContext());
            mNavNumber.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            
            //设置背景
            int roundRadius = 20; // 8dp 圆角半径
            int fillColor = defaultColor;//内部填充颜色
            GradientDrawable gd = new GradientDrawable();//创建drawable(动态创建shape)
            gd.setColor(fillColor);
            gd.setCornerRadius(roundRadius);
            mNavNumber.setBackground(gd);
            
            
            //设置边框
//            int strokeColor = Color.parseColor("#2E3135");//边框颜色
//            int strokeWidth = 5; // 3dp 边框宽度
//            gd.setStroke(strokeWidth, strokeColor);

            mNavNumber.setGravity(Gravity.CENTER);
            mNavNumber.setPadding(15, 6, 15, 6);
            mNavNumber.setText("0/0");
            mNavNumber.setTextColor(selectColor);
            LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.END | Gravity.BOTTOM;
            params.bottomMargin = navBottomMargin;
            params.rightMargin = navBottomMargin;
            addView(mNavNumber, params);
        }
    }


    private boolean touched = false;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touched = true;
                startX = (int) ev.getX();
                startY = (int) ev.getY();
                getParent().requestDisallowInterceptTouchEvent(true);
                setPlaying(false);
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();
                int moveY = (int) ev.getY();
                int disX = moveX - startX;
                int disY = moveY - startY;
                getParent().requestDisallowInterceptTouchEvent(2 * Math.abs(disX) > Math.abs(disY));
                setPlaying(false);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                setPlaying(true);
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        setPlaying(true);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        setPlaying(false);
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        if (visibility == View.GONE) {
            //页面不可见时停止轮播
            setPlaying(false);
        } else if (visibility == View.VISIBLE) {
            // 恢复可见时开始轮播
            setPlaying(true);
        }
        super.onWindowVisibilityChanged(visibility);
    }

    /**
     * height width ratio,宽高一个固定另一个不固定时才有效果
     */
    private float ratio = 0.5f;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取宽度的模式和尺寸
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        //获取高度的模式和尺寸
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);


        //宽确定,高不确定
        if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY && ratio != 0) {
            heightSize = (int) (widthSize * ratio + 0.5f);//根据宽度和比例计算高度
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
        } else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY & ratio != 0) {
            widthSize = (int) (heightSize / ratio + 0.5f);
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
        }

        //必须调用下面的两个方法之一完成onMeasure方法的重写,否则会报错
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public void setRatio(float ratio) {
        this.ratio = ratio;
    }

    /**
     * 设置导航点、条、数字颜色,数字颜色不用加selectColor
     * @param defaultColor unSelectColor
     * @param selectColor selectedColor
     */
    public void setNavColor(int defaultColor, int selectColor){
        this.defaultColor = defaultColor;
        this.selectColor = selectColor;
        if (mNavType == NAV_DOT || mNavType == NAV_BOTTOM_BAR) {
            if (defaultDrawable != null) {
                defaultDrawable.setColor(defaultColor);
            }
            if (selectedDrawable != null) {
                selectedDrawable.setColor(selectColor);
            }
        } else {
            if (mNavNumber != null) {
                mNavNumber.setTextColor(selectColor);
            }
        }

    }

    /**
     * set nav type
     * @param navType type of nav(dot bar or number)
     */
    public void setNavType(int navType) {
        if (navType != mNavType) {
            initNavView(navType);
            this.mNavType = navType;
        }
    }

    public void onDestroy() {
        setPlaying(false);
        mHandler.removeMessages(0);

        mRecyclerView.setAdapter(null);
        mRecyclerView = null;
        mData.clear();
        mData = null;
        mAdapter = null;
    }

    // 内置适配器
    private class RecyclerAdapter extends RecyclerView.Adapter implements OnClickListener {

        @NotNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            SimpleDraweeView img = new SimpleDraweeView(parent.getContext());
            RecyclerView.LayoutParams l = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            img.setScaleType(ImageView.ScaleType.CENTER_CROP);
            img.setLayoutParams(l);
            img.setId(R.id.icon);
            img.setOnClickListener(this);
            return new RecyclerView.ViewHolder(img) {
            };
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {//可自己修改使用哪种方式加载图片
//            ImageView img = (ImageView) holder.itemView.findViewById(R.id.icon);
            ((SimpleDraweeView) holder.itemView).setImageURI(mData.get(position % mData.size()).getUrl());
//            Glide.with(getContext()).load(mData.get(position % mData.size()).getUrl()).placeholder(R.mipmap.ic_launcher).error(R.drawable.arrow_left).into(img);
        }

        @Override
        public int getItemCount() {
            return mData == null ? 0 : mData.size();
        }

        @Override
        public void onClick(View v) {
            if (mPageClickListener != null) {
                mPageClickListener.onClick(mData.get(currentIndex));// TODO: 2017/7/6 返回位置或者广告链接
            }
        }
    }

    private class PagerSnapHelper extends LinearSnapHelper {

        @Override
        public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
            int targetPos = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
            final View currentView = findSnapView(layoutManager);
            if (targetPos != RecyclerView.NO_POSITION && currentView != null) {
                int currentPostion = layoutManager.getPosition(currentView);
                int first = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
                int last = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                currentPostion = targetPos < currentPostion ? last : (targetPos > currentPostion ? first : currentPostion);
                targetPos = targetPos < currentPostion ? currentPostion - 1 : (targetPos > currentPostion ? currentPostion + 1 : currentPostion);
            }
            return targetPos;
        }
    }

    private void changePoint() {
        if (mNavType == NAV_DOT || mNavType == NAV_BOTTOM_BAR) {
            if (mDotContainer != null && mDotContainer.getChildCount() > 0) {
                int childCount = mDotContainer.getChildCount();
                for (int i = 0; i < childCount; i++) {
                    ((ImageView) mDotContainer.getChildAt(i)).setImageDrawable(defaultDrawable);
                }
                if (currentIndex == 0) {
                    ((ImageView) mDotContainer.getChildAt(childCount - 1)).setImageDrawable(selectedDrawable);
                } else if (currentIndex == mData.size() - 1) {
                    ((ImageView) mDotContainer.getChildAt(0)).setImageDrawable(selectedDrawable);
                } else {
                    ((ImageView) mDotContainer.getChildAt(currentIndex - 1)).setImageDrawable(selectedDrawable);
                }
            }
        } else {
            mNavNumber.setText(String.format(Locale.CHINA, "%d/%d", currentIndex, mData.size() - 2));
        }
    }
}

注:项目重要引入fresco的依赖用于加载图片:
implementation ‘com.facebook.fresco:fresco:1.10.0’//展示相册列表
;当然也可以修改onBindViewHolder中加载图片方式(使用glide,picaso等),及设置为自己xml自定义布局

使用示例:



import android.app.Activity
import android.graphics.Color
import android.os.Bundle
import com.facebook.drawee.backends.pipeline.Fresco
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        Fresco.initialize(application)



        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var datas = ArrayList<BannerEnt>()
        datas.add(BannerEnt("https://csdnimg.cn/feed/20201014/e5d5833cb9cf1355dfcd2e31af0b9c0e.jpg", 0))
        datas.add(BannerEnt("https://csdnimg.cn/feed/20201013/1abff9365808a81798e6ab53c1101146.jpg", 1))
        datas.add(BannerEnt("https://csdnimg.cn/feed/20201013/9bc6b56dd7ae5771d192b764b7901aa3.png", 2))
        banner.setRatio(0.5f)
        banner.setNavType(2)
        banner.setNavColor(Color.parseColor("#ffff0000"), Color.parseColor("#ff00ff00"))
        banner.setDatas(datas)
    }
}

利用RecyclerView实现无限轮播广告条 代码地址如下:http://www.demodashi.com/demo/14660.html ####前言 之前有讲过TabLayout的一些知识, TabLayout实现顶部导航(一) TabLayout基本属性全解 但是对于TabLayout实现的导航栏仍是有诸多限制,例如不能任意设置text的文字大小,若导航中涉及到图片的话,图片只能简单的设计到文字上方,所以布局方面仍是很受限制,为了... 阅读详情

相关推荐

Android无限循环RecyclerView的完美实现方案

背景 项目中要实现横向列表的无限循环滚动,自然而然想到了RecyclerView,但我们常用的RecyclerView是不支持无限循环滚动的,所以就需要一些办法让它能够无限循环。 方案选择 方案1 对Adapter进行修改 网上大部分博客的解决方案都是这种方案,对Adapter做修改。具体如下 首先,让 Adapter 的 getItemCount() 方法返回 Integer.MAX_VALUE,使得position数据达到很大很大; 其次,在 onBindViewHolder() 方法里对position参数取余运算,拿到position对应的真实数据索引,然后对itemView绑定

使用最新的ViewPager2实现无限轮播图,ViewPager2是使用RecyclerView实现的,适配器的写法与使用RecyclerView类似

使用最新的ViewPager2实现无限轮播图,ViewPager2是使用RecyclerView实现的,适配器的写法与使用RecyclerView类似

qq_36570506的博客 3261

Python实现支付宝转账接口

由于工作需要使用python开发一个自动转账接口,记录一下开发过程。 首先需要在蚂蚁金服上申请开通开发者账户,有了开发者账户就可以使用沙箱进行开发了。 在开发之前我们需要在沙箱应用中填写密钥,密钥的获取可以使用阿里提供的工具包自动生成。 前期准备工作完成了,接下来是编写代码部分。主要用到了python-alipay-sdk库,使用pip安装即可,如果安装的过程中遇到问题推荐使用Anaconda...

FanMLei的博客 8516

Android kotlin 实现轮播图功能(Banner1.4.10+RecyclerView+BRVAH3.0.6+androidx)

11、图片点击事件,以上内容都可写成链式布局,这是轮播图的监听。3、播放到末尾后又重新回到开头。这依赖包还需要得到要添加,在。在添加以下代码,不添加就不行。,分别为6种样式和19种动画。1、动手/自动左右滑动。

彬sir哥的博客 3325

TC3xx系列LMU与SPR实战:将关键算法从Flash搬移至PSPR提升5倍执行效率

在实际电机控制项目中,通过将FOC算法全部迁移到PSPR,我们不仅将执行时间从56μs降至11μs,还将最坏情况下的时间偏差控制在±0.3μs以内。实测数据:在TC397上执行Flash中的32位浮点矩阵乘法,平均每条指令需要8.7个周期,而同样的代码在PSPR中仅需1.2个周期。传统开发中,工程师往往将所有代码放在Flash中运行,这相当于让F1赛车在乡村公路上行驶。迁移后不仅平均执行时间缩短,更重要的是时间抖动从±15%降低到±2%以内,这对闭环控制系统至关重要。不是所有代码都适合迁移到PSPR。

weixin_31421613的博客 298

UE4免费资产库新玩法:Quixel Bridge插件安装与Megascans资源导入全攻略

本文详细介绍了如何在UE4中安装Quixel Bridge插件并导入Megascans资源,帮助开发者快速获取高质量3D资产。通过分步教程和实用技巧,提升游戏或影视场景的制作效率,特别适合需要真实感环境的项目。

weixin_27729671的博客 369

Android——支持图片加视频无限轮播的banner

基于https://github.com/youth5201314/banner扩展,图片+视频无限轮播banner Demo地址 https://gitee.com/saqino/pic-video-banner-demo.git 说明 使用大佬的banner控件是很方便的,但是对视频+图片无限轮播的支持较弱,所以决定重写几个类实现功能。 不重写无法实现的原因如下: 无限轮播模式下,item大于1时, adapter会自动增加两个item,一个在最前,一个在最后,这样子做...

Saqino的博客 9886

使用HFSS仿真分支波导耦合器

本文介绍了分支波导耦合器的HFSS仿真设计过程。首先给出了器件关键参数(t=0.365mm,l=1.600mm等),详细说明了建模步骤:包括创建中心分支、设置变量参数、镜像复制两侧分支、矩形波导端口设计等操作。重点阐述了激励端口设置方法,包括四个端口的积分线绘制,以及求解频率设定。最后展示了S参数、幅度平衡度和相位差等关键性能指标的仿真结果提取方法。整个设计过程体现了HFSS在微波器件仿真中的参数化建模和结果分析能力。

shao666888的博客 180

项目实践-RecyclerView(二) - 卡片叠放侧滑

文章目录一 前言1.1参考资料与预期目标1.2 ItemTouchHelper与CallBack 一 前言 1.1参考资料与预期目标 玩转仿探探卡片式滑动效果 我用过这篇文章的开源库,但是我感觉不是特别好, 我想像岛读APP一样的效果 1.2 ItemTouchHelper与CallBack 详细看了一下参考文章,发现用到了了之前学习的CallBack ItemTouchHelper是干什么用的...

Wby_Nju的博客 1897

2026年高教社杯数学建模国赛A题解题思路:从物理方程推导到MATLAB高效求解的全流程实战指南

□所有代码能够从头运行到尾,不报错(清除workspace重新跑一遍)□论文中的每个图号、表号、公式编号与正文引用一致□附录中附上核心代码(注意:不是全部代码,而是关键求解器和后处理部分)□支撑材料压缩包包含完整代码、数据文件、README说明□摘要字数严格控制在1000字以内,突出创新点和核心结果□。

YOLO 110

【SECS】初识SECS协议

项目标题的第一位和第二位告诉下面有多少字节表示项目的长度。而项目的长度是指项目标题后面的字节数,这里第一个字节就是项目标题。1个字节可以表示的最大长度是0-255,所以只要项目标题后面的字节数小于等于254,都是0x01。

weixin_48618536的博客 1645

实现安卓无限轮播组件Banner

前言 前些天需要使用到安卓的banner,也就是现在主流app主页的无限轮播的横幅,现在已经有很多好的开源项目可以直接使用,不过我还是想自己去实现一遍。因为是访问的网络数据,实际过程中还是有些坑的,所以还是记录一下。 具体实现 首先还是来看看最终的效果,gif是有些卡顿,跑起来还是很流畅的 了解到,现在实现这种横幅,基本上是2种方式,一种是使用RecyclerView的横向滚动去实...

丶legend的博客 762

Android车载音频系统概览

官网有些部分的内容描述比较简单,对没有app、系统和底层开发经验,容易一眼扫过,没有留意到相关细节。 本节补充车载音频相关细节。

hwj的博客 785

banner项目实战案例:RecyclerView.Adapter集成轮播功能完整指南

在Android开发中,实现高效的轮播功能是提升用户体验的关键环节。本文将详细介绍如何使用banner项目快速实现RecyclerView.Adapter集成轮播功能,让你轻松掌握这一实用技能。 ## 一、准备工作:项目环境搭建 首先,确保你的开发环境已配置好。通过以下命令克隆banner项目到本地: ```bash git clone https://gitcode.com/gh_mirr

gitblog_00279的博客 255

(三)UPF之Domain Coverage Relationship(Cover、Equivalent、Independent)

整个Soc架构中一般会存在多个Power Domain,不同的Power Domain之间也存在着一定的Coverage关系。在Cadence工具中,这种。不同的Domain Coverage关系中,各个Domain存在着一定的关联()。

Mr.翟的博客 1424

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

banner项目源码解析:揭秘ViewPager2无限轮播的实现原理

在Android开发中,轮播图是App首页、活动页等场景的常见组件。banner项目作为一个专注于ViewPager2无限轮播功能的开源库,提供了极其简单的使用方式,支持自定义Indicator、一屏三页和仿魅族banner效果。本文将深入解析其核心实现原理,帮助开发者快速掌握ViewPager2无限轮播的设计思路。 ## 核心实现方案:数据循环与位置映射 ViewPager2本身并不直接支持

gitblog_00844的博客 4万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

一个不显示全屏图的banner无限自动轮播例子,利用recycleview实现类似viewpager效果

IncompleteScreenBanner 一个不显示全屏图的banner无限自动轮播例子,利用recycleview实现类似viewpager效果 背景 其实程序猿要开发一个demo的背景,都!一!样! 说什么为了社会进步,为了挑战自我,都!是!瞎!扯!蛋! 无非就是一个背景,产品经理要求实现该功能!!! 废话小说,先上gif为敬! 功能 正常来说,banner无限轮播,都是全屏的图片去轮...

小夫的博客 655

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

RecyclerBanner:用RecyclerView实现无限轮播图的终极解决方案

RecyclerBanner是一款基于RecyclerView实现的无限轮播图解决方案,提供普通版和3D版两种轮播效果,帮助Android开发者轻松实现流畅、高效的图片轮播功能。无论是应用首页的广告展示,还是内容推荐区域的图片轮播,RecyclerBanner都能满足你的需求。 ## 为什么选择RecyclerBanner? 在Android开发中,轮播图是一个非常常见的UI组件。传统的Vie

gitblog_01070的博客 440

Android轮播图-自定义无限滚动的广告Banner控件

今天闲来无事,梳理一下关于Android中广告banner图的一些技巧。 一般来说,我们的广告Banner要满足这样几个条件: Banner单个Item无限循环 自动滚动 响应单独item点击事件 触摸禁止滑动 指示条 画廊效果 ok,下面我们就针对这几点一一来进行分析 Banner单个Item无限循环 首先我们要实现一个自动滚动和手动均可滚动的Banner,很显然,我们需要使用...

xiaomi987的专栏 2635

Ascend-TLA · DeltaNet / NLP 样例

本目录是一个基于 **DeltaNet(Delta Rule)线性注意力**、面向**昇腾 NPU** 的实践样例,配套 **NLP 语言建模**训练流程与 Quick Start Notebook。更多说明与完整工程见上游仓库:[https://link.gitcode.com/i/aa99b23560f0be04f3bda1672b6fa3fa](https://link.gitcode.co

gitblog_00730的博客 467

RecyclerBanner常见问题解答:从集成到上线的避坑指南

RecyclerBanner是一款基于RecyclerView实现的无限轮播图组件,支持普通版和3D版轮播效果,广泛应用于Android应用的首页Banner、广告轮播等场景。本文整理了开发者在集成和使用RecyclerBanner过程中最常见的问题及解决方案,帮助你快速避坑,顺利上线。 ## 一、环境配置与依赖问题 ### 1.1 项目无法编译通过怎么办? 确保你的项目满足以下环境要求: -

gitblog_00151的博客 299

Android ViewPager2实现无限轮播

Android轮播控件 全新升级,基于ViewPager2实现无限轮播功能。可以自定义indicator,需自定义实现 Indicator 接口,内置了的IndicatorView,支持五种动画切换。支持传入RecyclerView.Adapter 即可实现无限轮播,支持任何ReyclerView.Apdater框架,集成使用请参考Sample。 支持自动轮播 支持一屏三页 支持自定义Indic...

utomi的博客 1万+

Android实现无限轮播功能(附带源码)

Android实现无限轮播功能(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1283

ViewPager,ViewPager2 无限轮播功能。自定义 Indicator,支持一屏三页,支持仿魅族 banner 效果。极其简单的使用方式

banner 项目地址:zguop/banner 简介: 🔥🔥ViewPager,ViewPager2 无限轮播功能。自定义 Indicator,支持一屏三页,支持仿魅族 banner 效果。极其简单的使用方式 更多:作者提 Bug 标签: 全新升级,基于ViewPager2实现无限轮播功能。可以自定义 indicator,需自定义实现Indicator接口,内置了的 IndicatorView,支持五种动画切换。支持传入 RecyclerView.Adapter 即...

未来很长,但我会努力的走下去。 2427

android banner框架_ViewPager2:打造Banner控件

作者丨utomi来源丨Android开发中文站https://juejin.im/post/5e49163e6fb9a07cb96ae33d基于ViewPager2实现无限轮播功能。支持传入RecyclerView.Adapter 即可实现无限轮播,原理上支持任何ReyclerView.Apdater框架。Viewpager2已经发布正式版,性能也优越于ViewPager,看过ViewP...

weixin_33823399的博客 1400

从入门到精通:banner项目ViewPager2轮播功能全方位教程

banner项目是一个专注于ViewPager和ViewPager2无限轮播功能的Android开源库,它提供了自定义Indicator、支持一屏三页和仿魅族banner效果等强大特性,使用方式极其简单。本教程将带你从入门到精通,轻松掌握banner项目的ViewPager2轮播功能。 ## 一、项目概述与核心优势 banner项目旨在为Android开发者提供简单易用且功能丰富的轮播解决方案

gitblog_00850的博客 248
上一篇: 微信小程序转快应用
下一篇: 阿里云腾讯云华为云端图片处理及优化
崔星星
博客等级 码龄10年 24粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值