千家信息网

如何用Android实现视图轮播效果

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,本篇内容主要讲解"如何用Android实现视图轮播效果",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何用Android实现视图轮播效果"吧!秒杀位置的轮
千家信息网最后更新 2025年01月18日如何用Android实现视图轮播效果

本篇内容主要讲解"如何用Android实现视图轮播效果",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何用Android实现视图轮播效果"吧!

秒杀位置的轮播

拆解

通过观察发现其实还是挺简单,大致分为

1、商品图片的上下轮播
2、价格布局渐隐渐现
在android上实现布局轮播,其实官方已经提供了实现
ViewFlipper
AdapterViewFlipper

由于后端传递的是一组商品,不确定个数。那么选取AdapterViewFlipper是最好的选择

布局复用,用adpter的方式填充数据

而且不论是ViewFlipper还是AdapterViewFlipper 系统都帮助实现了自动轮播的功能,我们只需要设置它的进入和退出动画就可以。
但上面的效果有一个和AdapterViewFlipper联动的效果,在布局移动到屏幕外面的过程中需要执行一个渐隐渐现的联动效果。
查看了上面两个布局,在调用showNext方法时没有提供改变时的监听,那没办法只能自己去实现。其实也简单,继承AdapterViewFlipper重写它的showNext方法就行了。

MFAdapterViewFlipper

/** * File description. * 自定义AdapterViewFlipper 在它执行下一个动画时回调给也无妨 * @author lihongjun * @date 9/24/21 */public class MFAdapterViewFlipper extends AdapterViewFlipper {    // view切换时的回调    private AdapterViewFlipperChangeListener adapterViewFlipperChangeListener;    public MFAdapterViewFlipper(Context context) {        super(context);    }    public MFAdapterViewFlipper(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MFAdapterViewFlipper(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public MFAdapterViewFlipper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    public void setAdapterViewFlipperChangeListener(AdapterViewFlipperChangeListener adapterViewFlipperChangeListener) {        this.adapterViewFlipperChangeListener = adapterViewFlipperChangeListener;    }    @Override    public void showNext() {        super.showNext();        if (adapterViewFlipperChangeListener != null) {            adapterViewFlipperChangeListener.showNext();        }    }    @Override    public void showPrevious() {        super.showPrevious();        if (adapterViewFlipperChangeListener != null) {            adapterViewFlipperChangeListener.showPrevious();        }    }    /**     * 布局切换时的回调     */    public interface AdapterViewFlipperChangeListener {        /**         * 显示后一个         */        void showNext();        /**         * 显示前一个         */        void showPrevious();    }}

动起来

接下来就是填充数据让他动起来了
为了让外面使用这个布局简单点,那自定义一下view吧

布局

                            

android:flipInterval="3000"
android:loopViews="true"
轮播间隔3秒
开启轮播布局

自定义view

/** * File description. * 首页秒杀位 图片轮播 * * @author lihongjun * @date 9/24/21 */public class HomeCountDownProductSwitch extends RelativeLayout implements MFAdapterViewFlipper.AdapterViewFlipperChangeListener {    // 一排固定展示2个    private static final int MAX_PRODUCT_SIZE = 2;    // 轮播布局    private MFAdapterViewFlipper mAdapterViewFlipper;    private HomeCountDownProductSwitchAdapter adapter;    // 价格整体布局    private View mVPrice;    private MFPriceViewB leftMFPriceView;    private MFPriceViewB rightMFPriceView;    // 当前轮播的位置    private int currentPosition = 0;    // 轮播的屏数    private int mFlipCount;    // 商品集合数据    List mProductList;    public HomeCountDownProductSwitch(Context context) {        this(context, null);    }    public HomeCountDownProductSwitch(Context context, AttributeSet attrs) {        super(context, attrs);        LayoutInflater.from(context).inflate(R.layout.home_count_down_product_switch, this);        mAdapterViewFlipper = findViewById(R.id.home_avf);        leftMFPriceView = findViewById(R.id.layout_left_price);        rightMFPriceView = findViewById(R.id.layout_right_price);        mVPrice = findViewById(R.id.ll_price);        mAdapterViewFlipper.setAdapterViewFlipperChangeListener(this);        adapter = new HomeCountDownProductSwitchAdapter(context);        mAdapterViewFlipper.setAdapter(adapter);    }    /**     * 设置展示数据     *     * @param productList     */    public void setProductList(List productList) {        mAdapterViewFlipper.stopFlipping();        this.mProductList = productList;        this.currentPosition = 0;        int productSize = CommonUtils.isEmpty(productList) ? 0 : productList.size();        // 每行展示2个 所以一共有多少行 等于2的整除加余数        mFlipCount = (productSize / MAX_PRODUCT_SIZE) + (productSize % MAX_PRODUCT_SIZE);        changeCurrentPrice();        adapter.setData(productList);        postDelayed(new Runnable() {            @Override            public void run() {                startFlipping();            }        },1000);    }    /**     * 开始轮播     */    private void startFlipping() {        mAdapterViewFlipper.setInAnimation(getContext(),R.animator.anim_count_down_product_in);        mAdapterViewFlipper.setOutAnimation(getContext(),R.animator.anim_count_down_product_out);        Animation priceOutAnimation = AnimationUtils.loadAnimation(getContext(),R.anim.home_anim_price_out);        priceOutAnimation.setDuration(500);        mAdapterViewFlipper.getOutAnimation().addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                mVPrice.startAnimation(priceOutAnimation);            }            @Override            public void onAnimationEnd(Animator animation) {                changeCurrentPrice();            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        mAdapterViewFlipper.startFlipping();    }    /**     * 更改当前价格模块     */    private void changeCurrentPrice() {        int productSize = MFCommonUtils.isEmpty(mProductList) ? 0 : mProductList.size();        // 数据不合法不显示价格        if (MFCommonUtils.isEmpty(mProductList) || productSize <= 0) {            mVPrice.setVisibility(GONE);            return;        }        // 每排展示两个商品数据        int start = currentPosition * MAX_PRODUCT_SIZE;        int end = start + 1;        TileBean.Product leftProduct = null;        TileBean.Product rightProduct = null;        // 左边的商品        if (productSize > start) {            leftProduct = mProductList.get(start);        }        // 右边的商品        if (productSize > end) {            rightProduct = mProductList.get(end);        }        leftMFPriceView.initPriceUI(leftProduct != null ? leftProduct.getPriceInfo() : null);        rightMFPriceView.initPriceUI(rightProduct != null ? rightProduct.getPriceInfo() : null);    }    /**     * 显示后一个     */    @Override    public void showNext() {        currentPosition ++;        // 如果已经循环了1轮 那从头开始        if (currentPosition == mFlipCount) {            currentPosition = 0;        }    }    /**     * 显示前一个     */    @Override    public void showPrevious() {    }    /**     * 布局适配器     */    private static final class HomeCountDownProductSwitchAdapter extends BaseAdapter {        private Context mContext;        // 商品列表        private List productList;        public HomeCountDownProductSwitchAdapter(Context context) {            this.mContext = context;        }        /**         * 更新数据         *         * @param         */        public void setData(List productList) {            this.productList = productList;            notifyDataSetChanged();        }        @Override        public int getCount() {            int count = 0;            if (MFCommonUtils.isEmpty(productList)) {                return count;            }            // 每行展示2个 所以一共有多少行 等于2的整除加余数            count = (productList.size() / MAX_PRODUCT_SIZE) + (productList.size() % MAX_PRODUCT_SIZE);            return count;        }        @Override        public Object getItem(int position) {            return productList == null ? null : productList.get(position);        }        @Override        public long getItemId(int position) {            return 0;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder;            if (convertView == null) {                convertView = LayoutInflater.from(mContext).inflate(R.layout.home_page_tile_time_down_holder_flipper, null);                holder = new ViewHolder(convertView);                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            // 设置数据            // 每排展示两个商品数据            int start = position * MAX_PRODUCT_SIZE;            int end = start + 1;            int productSize = MFCommonUtils.isEmpty(productList) ? 0 : productList.size();            TileBean.Product leftProduct = null;            TileBean.Product rightProduct = null;            // 左边的商品            if (productSize > start) {                leftProduct = productList.get(start);            }            // 右边的商品            if (productSize > end) {                rightProduct = productList.get(end);            }            holder.bindData(leftProduct, rightProduct, position);            return convertView;        }    }    // holder    private static final class ViewHolder {        private View itemView;        // 左边和有点两个布局控件        private ImageView mIvLeft;        private ImageView mIvRight;        private int imageRadio;        public ViewHolder(View itemView) {            this.itemView = itemView;            mIvLeft = itemView.findViewById(R.id.iv_left_img);            mIvRight = itemView.findViewById(R.id.iv_right_img);            imageRadio = itemView.getResources().getDimensionPixelSize(R.dimen.margin_8);        }        /**         * 设置数据         *         * @param leftProduct  左边的商品         * @param rightProduct 右边的商品         */        public void bindData(TileBean.Product leftProduct, TileBean.Product rightProduct, int position) {            // 如果这一排都没商品则隐藏            if (leftProduct == null && rightProduct == null) {                itemView.setVisibility(View.GONE);                return;            }            itemView.setVisibility(View.VISIBLE);            if (leftProduct != null) {                GlideHelper.loadRoundAndGifImage(mIvLeft, leftProduct.getImage(), imageRadio, R.drawable.ic_default_50);            }            if (rightProduct != null) {                GlideHelper.loadRoundAndGifImage(mIvRight, rightProduct.getImage(), imageRadio, R.drawable.ic_default_50);            }        }    }}

注意点在于

1、进入和退出动画必须是属性动画
2、当前滚动的屏数,根据它可以算出对应的postion

* 显示后一个*/@Overridepublic void showNext() {    currentPosition ++;    // 如果已经循环了1轮 那从头开始    if (currentPosition == mFlipCount) {        currentPosition = 0;    }}

在执行out动画时,执行价格布局的渐隐渐现动画

mAdapterViewFlipper.getOutAnimation().addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                mVPrice.startAnimation(priceOutAnimation);            }            @Override            public void onAnimationEnd(Animator animation) {                changeCurrentPrice();            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });

执行渐隐渐现动画时显示的是上一个价格,在动画执行完毕后设置当前应该展示的价格

到此,相信大家对"如何用Android实现视图轮播效果"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0