Android实现轮播控件Banner

news2024/12/28 18:02:13

背景

最近做需求要实现一个轮播图,最后通过Handler+ViewPager实现了需求,所以把实现的过程总结一下,方便以后学习参考,以下是轮播图的效果:

实现思路

  • 定时轮播
    利用Handler+ViewPager,Handler发送定时消息切换ViewPager的页面

  • 无限轮播效果
    在这里插入图片描述

如果我们只是在自动轮播到最后一页 然后进行判断让切换到第一页 这样是可以实现轮播的效果,但是 有两个问题
切换从最后一页切换到第一页的时候有一个很明显的回滚效果 不是我们想要的
当我们手动滑动的时候 在第一页和最后一页的时候 无法继续左右滑动 因为已经没有下一页了

在第一页前面插入一个最后一页,在最后一页后面插入一个第一页,这样用户在第一页继续向右滑动时,便可滑动看到最后一页,同理,用户在最后一页向左滑动时便可滑动到第一页。

用户虽然只看到三张图片,实际上却是五张,当在view4的时候自动切换到view5时,进行判断让到切换到view2,这样造成的感觉就是最后一张下来是第一张,当在view2的时候切换到view1时,进行判断让切换到view4。

我们利用viewpage自带的方法切换界面立即切换没有滚动效果 当图片一样的时候是看不出图片变化的

setCurrentItem(int item, boolean smoothScroll)
第二个参数设置false 界面切换的时候无滚动效果 默认true

下面是代码实现
layout_banner.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/banner_view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_gravity="bottom"
        android:orientation="horizontal"
        android:gravity="center_vertical"
        android:background="#33000000">
        <!-- 标题-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:layout_marginStart="10dp"
            android:layout_gravity="start"
            android:id="@+id/banner_title"
            tools:text="title"/>
        <!-- 小圆点-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/banner_indicator"
            android:orientation="horizontal"
            android:gravity="end"
            android:layout_marginEnd="10dp"
            android:padding="10dp">
        </LinearLayout>
    </LinearLayout>

</FrameLayout>

BannerViewPager.java

package com.ryd.banner.banner;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.ryd.banner.R;
import com.ryd.banner.Utils;

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

/**
 * @author : ruanyandong
 * @e-mail : ruanyandong@didiglobal.com
 * @date : 12/29/22 4:23 PM
 * @desc : com.ryd.banner
 */
public class BannerViewPager extends FrameLayout {

    private ViewPager viewPager;
    private TextView tvTitle;
    private LinearLayout indicatorGroup;
    private BannerAdapter adapter;
    private List<String> titles;//标题集合
    private List imageUrls;//图片数据
    private List<View> views;//轮播图显示
    private ImageView[] tips;//保存显示的小圆点
    private int count;//保存imageUrls的总数
    private int bannerTime = 2500;//轮播图的间隔时间
    private int currentItem = 0;//轮播图的当前选中项
    private long releaseTime = 0;//保存触发时手动滑动的时间 进行判断防止滑动之后立即轮播
    private final int START = 10;
    private final int STOP = 20;
    private Context context;
    private Handler handler;

    private final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            long now = System.currentTimeMillis();
            if (now - releaseTime > bannerTime - 500) {
                handler.sendEmptyMessage(START);
            } else {
                handler.sendEmptyMessage(STOP);
            }
        }
    };


    public BannerViewPager(Context context) {
        super(context);
    }

    public BannerViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        titles = new ArrayList<>();
        titles.add("标题1");
        titles.add("标题2");
        titles.add("标题3");
        imageUrls = new ArrayList();
        views = new ArrayList<>();
        init(context, attrs);
    }


    private void init(final Context context, AttributeSet attrs) {
        View view = LayoutInflater.from(context).inflate(R.layout.layout_banner, this);
        viewPager = (ViewPager) view.findViewById(R.id.banner_view_pager);
        tvTitle = (TextView) view.findViewById(R.id.banner_title);
        indicatorGroup = (LinearLayout) view.findViewById(R.id.banner_indicator);
        handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case START:
                        viewPager.setCurrentItem(currentItem + 1);
                        handler.removeCallbacks(runnable);
                        handler.postDelayed(runnable, bannerTime);
                        break;
                    case STOP:
                        releaseTime = 0;
                        handler.removeCallbacks(runnable);
                        handler.postDelayed(runnable, bannerTime);
                        break;
                }
            }
        };
    }

    /**
     * 初始化数据 以及拿到数据后的各种设置
     * 可以是网络地址 也可是项目图片数据
     *
     * @param imageUrls
     */
    public void setData(List<?> imageUrls) {
        this.imageUrls.clear();
        this.count = imageUrls.size();

        //this.imageUrls.add(imageUrls.get(count-1));
        this.imageUrls.addAll(imageUrls);
        //this.imageUrls.add(imageUrls.get(0));

        initIndicator();
        getShowView();
        setUI();
    }

    /**
     * 设置标题
     *
     * @param titles
     */
    public void setTitles(List<String> titles) {
        this.titles.clear();
        this.titles.addAll(titles);
    }

    /**
     * 设置小圆点指示器
     */
    private void initIndicator() {
        tips = new ImageView[count-2];
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        layoutParams.height = Utils.dip2px(context,10);
        layoutParams.width = Utils.dip2px(context,10);
        layoutParams.leftMargin = Utils.dip2px(context,5);// 设置点点点view的左边距
        layoutParams.rightMargin = Utils.dip2px(context,5);// 设置点点点view的右边距
        for (int i = 0; i < count-2; i++) {
            ImageView imageView = new ImageView(context);
            if (i == 0) {
                imageView.setBackgroundResource(R.drawable.shape_circle_red);
            } else {
                imageView.setBackgroundResource(R.drawable.shape_circle_white);
            }

            tips[i] = imageView;
            indicatorGroup.addView(imageView, layoutParams);
        }
    }

    /**
     * 获取显示图片view
     */
    private void getShowView() {
        for (int i = 0; i < imageUrls.size(); i++) {
            ImageView imageView = new ImageView(context);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            if (imageUrls.get(i) instanceof String) {

            } else {
                imageView.setImageResource((Integer) imageUrls.get(i));
            }
            views.add(imageView);
        }
    }

    /**
     * 设置UI
     */
    private void setUI() {
        adapter = new BannerAdapter();
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(onPageChangeLis);
        viewPager.setCurrentItem(1);
        handler.postDelayed(runnable, bannerTime);
    }


    // 第一页到第二页
    //  onPageScrollStateChanged: state 1
    //  onPageScrolled: position 0 positionOffset 0.031481482 positionOffsetPixels 34
    //  onPageScrolled: position 0 positionOffset 0.107407406 positionOffsetPixels 116
    //  onPageScrolled: position 0 positionOffset 0.18888889 positionOffsetPixels 204
    //  onPageScrolled: position 0 positionOffset 0.20462963 positionOffsetPixels 221
    //  onPageScrollStateChanged: state 2
    //  onPageSelected: position 1
    //  onPageScrolled: position 0 positionOffset 0.28148147 positionOffsetPixels 304
    //  onPageScrolled: position 0 positionOffset 0.44351852 positionOffsetPixels 479
    //  onPageScrolled: position 0 positionOffset 0.5685185 positionOffsetPixels 614
    //  onPageScrolled: position 0 positionOffset 0.675 positionOffsetPixels 729
    //  onPageScrolled: position 0 positionOffset 0.7592593 positionOffsetPixels 820
    //  onPageScrolled: position 0 positionOffset 0.82222223 positionOffsetPixels 888
    //  onPageScrolled: position 0 positionOffset 0.87314814 positionOffsetPixels 943
    //  onPageScrolled: position 0 positionOffset 0.912037 positionOffsetPixels 985
    //  onPageScrolled: position 0 positionOffset 0.9388889 positionOffsetPixels 1014
    //  onPageScrolled: position 0 positionOffset 0.96018517 positionOffsetPixels 1037
    //  onPageScrolled: position 0 positionOffset 0.975 positionOffsetPixels 1053
    //  onPageScrolled: position 0 positionOffset 0.98425925 positionOffsetPixels 1063
    //  onPageScrolled: position 0 positionOffset 0.9916667 positionOffsetPixels 1071
    //  onPageScrolled: position 0 positionOffset 0.9953704 positionOffsetPixels 1075
    //  onPageScrolled: position 0 positionOffset 0.99814814 positionOffsetPixels 1078
    //  onPageScrolled: position 0 positionOffset 0.9990741 positionOffsetPixels 1079
    //  onPageScrolled: position 1 positionOffset 0.0 positionOffsetPixels 0
    //  onPageScrollStateChanged: state 0

    // 第二页到第三页
    // onPageScrollStateChanged: state 1
    // onPageScrolled: position 1 positionOffset 0.01111114 positionOffsetPixels 12
    // onPageScrolled: position 1 positionOffset 0.06666672 positionOffsetPixels 72
    // onPageScrolled: position 1 positionOffset 0.1240741 positionOffsetPixels 134
    // onPageScrolled: position 1 positionOffset 0.19259262 positionOffsetPixels 208
    // onPageScrolled: position 1 positionOffset 0.2527778 positionOffsetPixels 273
    // onPageScrolled: position 1 positionOffset 0.27592587 positionOffsetPixels 297
    // onPageScrollStateChanged: state 2
    // onPageSelected: position 2
    // onPageScrolled: position 1 positionOffset 0.30277777 positionOffsetPixels 327
    // onPageScrolled: position 1 positionOffset 0.4074074 positionOffsetPixels 440
    // onPageScrolled: position 1 positionOffset 0.4990741 positionOffsetPixels 539
    // onPageScrolled: position 1 positionOffset 0.57407403 positionOffsetPixels 619
    // onPageScrolled: position 1 positionOffset 0.64444447 positionOffsetPixels 696
    // onPageScrolled: position 1 positionOffset 0.70092595 positionOffsetPixels 757
    // onPageScrolled: position 1 positionOffset 0.7537037 positionOffsetPixels 814
    // onPageScrolled: position 1 positionOffset 0.79814816 positionOffsetPixels 862
    // onPageScrolled: position 1 positionOffset 0.8342593 positionOffsetPixels 901
    // onPageScrolled: position 1 positionOffset 0.8666667 positionOffsetPixels 936
    // onPageScrolled: position 1 positionOffset 0.89351857 positionOffsetPixels 965
    // onPageScrolled: position 1 positionOffset 0.91481483 positionOffsetPixels 988
    // onPageScrolled: position 1 positionOffset 0.9342593 positionOffsetPixels 1009
    // onPageScrolled: position 1 positionOffset 0.94907403 positionOffsetPixels 1025
    // onPageScrolled: position 1 positionOffset 0.96111107 positionOffsetPixels 1038
    // onPageScrolled: position 1 positionOffset 0.9703704 positionOffsetPixels 1048
    // onPageScrolled: position 1 positionOffset 0.97870374 positionOffsetPixels 1057
    // onPageScrolled: position 1 positionOffset 0.98425925 positionOffsetPixels 1063
    // onPageScrolled: position 1 positionOffset 0.98888886 positionOffsetPixels 1068
    // onPageScrolled: position 1 positionOffset 0.9925926 positionOffsetPixels 1072
    // onPageScrolled: position 1 positionOffset 0.9944445 positionOffsetPixels 1074
    // onPageScrolled: position 1 positionOffset 0.9962963 positionOffsetPixels 1076
    // onPageScrolled: position 1 positionOffset 0.9981482 positionOffsetPixels 1078
    // onPageScrolled: position 1 positionOffset 0.9990741 positionOffsetPixels 1079
    // onPageScrolled: position 2 positionOffset 0.0 positionOffsetPixels 0
    // onPageScrollStateChanged: state 0

    // 第三页到第二页
    // onPageScrollStateChanged: state 1
    // onPageScrolled: position 1 positionOffset 0.95277774 positionOffsetPixels 1029
    // onPageScrolled: position 1 positionOffset 0.88796294 positionOffsetPixels 959
    // onPageScrolled: position 1 positionOffset 0.83611107 positionOffsetPixels 902
    // onPageScrolled: position 1 positionOffset 0.82592595 positionOffsetPixels 892
    // onPageScrollStateChanged: state 2
    // onPageSelected: position 1
    // onPageScrolled: position 1 positionOffset 0.7851852 positionOffsetPixels 848
    // onPageScrolled: position 1 positionOffset 0.66388893 positionOffsetPixels 717
    // onPageScrolled: position 1 positionOffset 0.55277777 positionOffsetPixels 597
    // onPageScrolled: position 1 positionOffset 0.45648146 positionOffsetPixels 492
    // onPageScrolled: position 1 positionOffset 0.3787037 positionOffsetPixels 409
    // onPageScrolled: position 1 positionOffset 0.30833328 positionOffsetPixels 332
    // onPageScrolled: position 1 positionOffset 0.2490741 positionOffsetPixels 269
    // onPageScrolled: position 1 positionOffset 0.20092595 positionOffsetPixels 217
    // onPageScrolled: position 1 positionOffset 0.1592592 positionOffsetPixels 171
    // onPageScrolled: position 1 positionOffset 0.1240741 positionOffsetPixels 134
    // onPageScrolled: position 1 positionOffset 0.09722221 positionOffsetPixels 104
    // onPageScrolled: position 1 positionOffset 0.07407403 positionOffsetPixels 79
    // onPageScrolled: position 1 positionOffset 0.055555582 positionOffsetPixels 60
    // onPageScrolled: position 1 positionOffset 0.041666627 positionOffsetPixels 44
    // onPageScrolled: position 1 positionOffset 0.030555606 positionOffsetPixels 33
    // onPageScrolled: position 1 positionOffset 0.021296263 positionOffsetPixels 22
    // onPageScrolled: position 1 positionOffset 0.014814854 positionOffsetPixels 16
    // onPageScrolled: position 1 positionOffset 0.010185242 positionOffsetPixels 11
    // onPageScrolled: position 1 positionOffset 0.0064815283 positionOffsetPixels 7
    // onPageScrolled: position 1 positionOffset 0.004629612 positionOffsetPixels 4
    // onPageScrolled: position 1 positionOffset 0.0027778149 positionOffsetPixels 3
    // onPageScrolled: position 1 positionOffset 9.2589855E-4 positionOffsetPixels 0
    // onPageScrolled: position 1 positionOffset 0.0 positionOffsetPixels 0
    // onPageScrollStateChanged: state 0

    // 第二页到第一页
    // onPageScrollStateChanged: state 1
    // onPageScrolled: position 0 positionOffset 0.9592593 positionOffsetPixels 1036
    // onPageScrolled: position 0 positionOffset 0.8666667 positionOffsetPixels 936
    // onPageScrolled: position 0 positionOffset 0.75185186 positionOffsetPixels 812
    // onPageScrolled: position 0 positionOffset 0.7185185 positionOffsetPixels 776
    // onPageScrollStateChanged: state 2
    // onPageSelected: position 0
    // onPageScrolled: position 0 positionOffset 0.65185183 positionOffsetPixels 704
    // onPageScrolled: position 0 positionOffset 0.46203703 positionOffsetPixels 499
    // onPageScrolled: position 0 positionOffset 0.31851852 positionOffsetPixels 344
    // onPageScrolled: position 0 positionOffset 0.21851853 positionOffsetPixels 236
    // onPageScrolled: position 0 positionOffset 0.14166667 positionOffsetPixels 153
    // onPageScrolled: position 0 positionOffset 0.08796296 positionOffsetPixels 95
    // onPageScrolled: position 0 positionOffset 0.053703703 positionOffsetPixels 58
    // onPageScrolled: position 0 positionOffset 0.030555556 positionOffsetPixels 33
    // onPageScrolled: position 0 positionOffset 0.015740741 positionOffsetPixels 17
    // onPageScrolled: position 0 positionOffset 0.0074074073 positionOffsetPixels 8
    // onPageScrolled: position 0 positionOffset 0.0027777778 positionOffsetPixels 3
    // onPageScrolled: position 0 positionOffset 9.259259E-4 positionOffsetPixels 1
    // onPageScrolled: position 0 positionOffset 0.0 positionOffsetPixels 0
    // onPageScrollStateChanged: state 0
    /**
     * viewPage改变监听
     * 用于响应所选页面
     */
    private ViewPager.OnPageChangeListener onPageChangeLis = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            Log.d("ruanyandong", "onPageScrolled: position "+position+" positionOffset "+positionOffset+" positionOffsetPixels "+positionOffsetPixels);
            // 第一页到第二页  position 0->1  positionOffset 0->1->0  positionOffsetPixels 0->划过一页的距离->0
            // 第二页到第三页  position 1->2  positionOffset 0->1->0  positionOffsetPixels 0->划过一页的距离->0
            // 第三页到第二页  position 一直是1  positionOffset 1->0  positionOffsetPixels 一页的距离->0
            // 第二页到第一页  position 一直是0  positionOffset 1->0  positionOffsetPixels 一页的距离->0
        }

        @Override
        public void onPageSelected(int position) {
            Log.d("ruanyandong", "onPageSelected: position "+position);
            // 每滑动一次都只打印一次方法,position打印最终选定页面的下标

            //计算当前页的下标,用于指示器改变
            int max = views.size() - 1;
            int temp = position;
            currentItem = position;
            if (position == 0) { // 当滑动到下标为0时,其实对于用户来说看到的是最后一个,所以需要将下标替换成倒数第二个
                currentItem = max - 1;
            } else if (position == max) {// 当滑动到最后一个时,其实对于用户来说看到的是第一个,所以需要将下标替换成正数第二个
                currentItem = 1;
            }
            temp = currentItem - 1;
            setIndicatorAndTitle(temp);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            currentItem = viewPager.getCurrentItem();
            Log.d("ruanyandong", "onPageScrollStateChanged: state "+state+" currentItem "+currentItem);
            // 0 静止  1 正在拖拽   2 松手后自动滑动
            // 每次拖动的状态变化都是 1->2->0  每次拖动一页,都会调用3次方法,依次打印1->2->0
            switch (state) {
                case 0: // 静止状态
                    //Log.e("aaa","=====静止状态======");
                    if (currentItem == 0) {
                        viewPager.setCurrentItem(count-2, false);
                    } else if (currentItem == count - 1) {
                        viewPager.setCurrentItem(1, false);
                    }
                    break;
                case 1: // 拖拽状态
//    Log.e("aaa","=======手动拖拽滑动时调用====");
                    releaseTime = System.currentTimeMillis();
                    if (currentItem == count - 1) {
                        viewPager.setCurrentItem(1, false);
                    } else if (currentItem == 0) {
                        viewPager.setCurrentItem(count-2, false);
                    }
                    break;
                case 2: // 松手自动滑动状态
//    Log.e("aaa","=======自动滑动时调用====");
                    break;
            }
        }
    };


    /**
     * 设置指示器和标题切换
     *
     * @param position
     */
    private void setIndicatorAndTitle(int position) {
        tvTitle.setText(titles.get(position));

        for (int i = 0; i < tips.length; i++) {
            if (i == position) {
                tips[i].setBackgroundResource(R.drawable.shape_circle_red);
            } else {
                tips[i].setBackgroundResource(R.drawable.shape_circle_white);
            }
        }
    }

    /**
     * 适配器
     */
    class BannerAdapter extends PagerAdapter {

        /**
         * 返回可用的视图数量
         * @return
         */
        @Override
        public int getCount() {
            return views.size();
        }


        /**
         * 判断当前View是否是来自于object
         * @param view
         * @param object
         * @return
         */
        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }

        /**
         * 创建初始化View,如果总共有三个View,刚开始会创建好第一二两个,当从第一个滑动到第二个时,会创建第三个view
         * @param container
         * @param position
         * @return
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(views.get(position));
            return views.get(position);
        }

        /**
         * 销毁view,当滑动到第三个时会销毁第一个,当滑动到第一个时会销毁第三个
         * @param container
         * @param position
         * @param object
         */
        @Override
        public void destroyItem(ViewGroup container, int position, @NonNull Object object) {
            container.removeView((View) object);
        }


    }

}

layout_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".banner.MainActivity">

    <com.ryd.banner.banner.BannerViewPager
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="200dp"/>

</FrameLayout>

MainActivity.java

package com.ryd.banner.banner;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import com.ryd.banner.R;
import com.ryd.banner.viewpager2.ViewPager2Activity;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BannerViewPager banner= (BannerViewPager) findViewById(R.id.banner);
        List<Integer> imageUrl=new ArrayList<>();
        imageUrl.add(R.drawable.water); // 当用户在第一页时,向右拖拽左滑时新增一个最后一页,让用户以为滑到了最后一页
        imageUrl.add(R.drawable.bubble);// 1 用户看到的第一页
        imageUrl.add(R.drawable.grass);// 2 用户看到的第二页
        imageUrl.add(R.drawable.water);// 3 用户看到的第三页
        imageUrl.add(R.drawable.bubble);// 当用户在第三页时,向左拖拽右滑时新增一个第一页,让用户以为滑到了第一页
        banner.setData(imageUrl);

    }


}

最后附上代码的github地址
参考
简单实现android轮播图

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

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

相关文章

初探Scala

目录 Scala介绍 Scala 环境搭建 IDEA新建Maven工程 创建执行输出Hello Scala Scala中main方法语法的详细解读 class 和 object 说明 Scala介绍 一般来说&#xff0c;学 Scala 的人&#xff0c;都会 Java&#xff0c;而 Scala 是基于 Java 的&#xff0c;因此我们需要将 S…

CSS基础总结(五)定位

文章目录 1.为什么需要定位 2.定位的组成 2.1公式 2.2定位模式 2.2.1静态定位static 2.2.2相对定位relative 2.2.3绝对定位absolute 2.2.4固定定位fixed 2.2.5粘性定位sticky 总结 2.3边偏移 3.定位叠放次序 4.定位拓展 4.1子绝父相布局法 4.2固定于版心右侧位置方…

read and write

read and write The read and write methods both perform a similar task, that is, copying data from and to application code. Therefore, their prototypes are pretty similar, and its worth introducing them at the same time: read 和 write 方法都执行类似的任务&…

Java开发 - 常用算法深度讲解,让你再也不会忘记

目录 前言 冒泡排序 原理 选择排序 原理 插入排序 原理 二分查找排序 原理 结语 前言 经常会有一些算法&#xff0c;我们说常用不常用&#xff0c;说不用也偶尔会用&#xff0c;当时看记住了&#xff0c;过几天提起来又忘记了&#xff0c;这是为什么呢&#xff1f;以…

Spring Security:PasswordEncoder密码加密匹配操作

目录 PasswordEncoder SpringBoot&#xff1a;注入BSryptPasswordEncoder实例 BSryptPasswordEncoder详解 父接口PasswordEncoder BSryptPasswordEncoder及其使用 成员方法 SecurityUtils安全服务工具类 测试代码 PasswordEncoder PasswordEncoder是Spring Security框架…

51单片机学习笔记_4 IO扩展:LED 点阵

IO 扩展(串转并)-74HC595 前面接的一些输入输出设备都是直接连接的单片机 IO 口&#xff0c;单片机仅有的 IO 口非常有限。而使用 IO 扩展可以大量增加可使用的端口。比如后面要使用的 LED 点阵&#xff0c;8*8个格子&#xff0c;使用扩展 IO 输入就更为合适。如果多级联一个&…

20230102单独编译原厂RK3588开发板的开发板rk3588-evb1-lp4-v10的Android12的内核2

20230102单独编译原厂RK3588开发板的开发板rk3588-evb1-lp4-v10的Android12的内核2 2023/1/2 21:01 《RK3588_Android12_SDK_Developer_Guide_CN.pdf》 原厂的开发板rk3588-evb1-lp4-v10单独编译内核的方式&#xff1a; cd kernel-5.10 export PATH../prebuilts/clang/host/lin…

educoder数据结构与算法 队列 第1关:实现一个顺序存储的队列

本文已收录于专栏 &#x1f332;《educoder数据结构与算法_大耳朵宋宋的博客-CSDN博客》&#x1f332; 目录 任务描述 相关知识 编程要求 测试说明 AC_Code 任务描述 本关任务&#xff1a;实现 step1/SeqQueue.cpp 中的SQ_IsEmpty、SQ_IsFull、SQ_Length、SQ_In和SQ_Out…

ceph集群搭建

一、环境准备 1.1、服务器准备 操作系统服务器IP服务器规格centos7.6192.168.161.114C/8Gcentos7.6192.168.161.124C/8Gcentos7.6192.168.161.134C/8G 1.2、服务器环境准备 1.2.1 更改主机名并添加映射 更改主机名 [rootlocalhost ~]# hostnamectl set-hostname ceph01 ##或…

内存池算法简单剖析

为什么要引入内存池算法? 我们知道C/C 语言中通过 malloc 调用 sbrk 和 mmap 这两个系统调用&#xff0c;向操作系统申请堆内存。但是&#xff0c;sbrk 和 mmap 这两个系统调用分配内存效率比较低&#xff0c;因为&#xff0c;执行系统调用是要进入内核态的&#xff0c;这样内…

区块链知识系列 - Oracle预言机

Oracle 预言机 区块链外信息写入区块链内的机制&#xff0c;一般被称为预言机&#xff08;oracle mechanism&#xff09;。 借助预言机外界的数据得以灌入链内, 使得DApp的玩法更多样. 比如DApp倚重的随机数, 可以考虑让一个硬件产生真随机数, 通过Oracle,定时灌入, 这将更公…

单机Docker部署应用Kraft模式的Kafka集群

单机Docker部署应用Kraft模式的Kafka集群1 Docker镜像准备1.1 下载Kafka1.2 配置容器1.3 修改kafka配置2 部署Kafka集群2.1 启动节点容器2.2 生成一个 Cluster ID2.3 格式化存储目录2.4 启动kafka服务3 知识3.1 控制器服务器3.2 进程角色3.3 仲裁投票者3.4 Kafka存储工具3.5 缺…

久泰新材料在港上市申请失效:年亏损超2亿元,崔轶钧为董事长

近日&#xff0c;贝多财经从港交所了解到&#xff0c;内蒙古久泰新材料科技股份有限公司&#xff08;下称“久泰集团”或“久泰新材料”&#xff09;在港交所的上市申请材料&#xff08;招股书&#xff09;已“失效”&#xff0c;目前已经无法正常查看或下载。 其中&#xff0c…

Hack the Box CTF 网络流量分析 中等难度 Penetrated | Wireshark

这是一道Hack the Box网络流量分析题&#xff0c;中等难度&#xff0c;题目本身就是一个 pcap 包。 1. 题目&#xff1a; 原文件链接如下&#xff0c;有兴趣可以自己先看一看&#xff1a; 链接: https://pan.baidu.com/s/16KLwQuoYA1AfEwuK78bBWg 提取码: 8864 Flag 格式&am…

Nginx内存管理源码剖析注解

文章目录Nginx内存池总览内存池中变量类型定义创建内存池&#xff1a;ngx_create_pool内存池分配空间&#xff1a;ngx_palloc小块内存空间分配&#xff1a;ngx_palloc_small创建小块内存池&#xff1a;ngx_palloc_block大块内存空间分配&#xff1a;ngx_palloc_large<br /&g…

【电动车】主动配电网多源协同运行优化研究——大规模电动汽车的蒙特卡洛模拟(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

TiDB问题排查

TiDB 集群问题导图 1. 服务不可用 1.1 客户端报 "Region is Unavailable" 错误 1.1.1 "Region is Unavailable" 一般是由于 region 在一段时间不可用导致&#xff08;可能会遇到 "TiKV server is busy" 或者发送给 TiKV 的请求由于 not leader…

JMM内存模型

借鉴&#xff1a; 一文带你搞懂JMM内存模型和JVM内存区域_Apple_Web的博客-CSDN博客_jmm内存模型和jvm内存模型的区别 面试官问我什么是JMM_java技术爱好者_R的博客-CSDN博客_jmm Java内存模型 概述 Java内存模型(即Java Memory Model&#xff0c;简称JMM)本身是一种抽象的…

箭头函数带来的this变化实例

1.不使用箭头函数时 let Lesson {site: 后盾人,lists:[js,css,mysql],show: function (param) { console.log(this);// {site: 后盾人, lists: Array(3), show: ƒ}return this.lists.map(function(title){console.log(this);// Window {window: Window, self: Window, docume…

17. 老板让我手动控制网页渲染速度,说这能反爬虫?我信了。

手动数据延迟加载&#xff0c;真的可以反爬虫 爬虫训练场项目&#xff0c;加速更新中&#xff0c;专栏清单参考 pachong.vip 本次案例需要的代码量特别小&#xff0c;所以咱们再 Nginx 中也进行一下相关配置 文章目录页面逻辑实现接口逻辑实现延迟实现&#xff0c;time.sleep()…