Android原生实现控件圆角方案(API28及以上)

news2024/9/29 15:35:18

Android控件的圆角效果的实现方式有很多种,这里介绍一下另一种Android原生的圆角实现方案(API28及以上)。

我们利用ShapeAppearanceModel、MaterialShapeDrawable来实现一个圆角/切角的Button。

实现效果如下图
在这里插入图片描述
我们在为控件添加阴影的基础上实现为控件添加shape的功能.

属性

增加自定义属性:

        <attr name="carbon_cornerRadiusTopStart" />
        <attr name="carbon_cornerRadiusTopEnd" />
        <attr name="carbon_cornerRadiusBottomStart" />
        <attr name="carbon_cornerRadiusBottomEnd" />
        <attr name="carbon_cornerRadius" />

        <attr name="carbon_cornerCutTopStart" />
        <attr name="carbon_cornerCutTopEnd" />
        <attr name="carbon_cornerCutBottomStart" />
        <attr name="carbon_cornerCutBottomEnd" />
        <attr name="carbon_cornerCut" />

创建ShapeModelView接口

创建通用的shape接口

public interface ShapeModelView {
    void setShapeModel(ShapeAppearanceModel shapeModel);
    ShapeAppearanceModel getShapeModel();

    void setCornerCut(float cornerCut);

    void setCornerRadius(float cornerRadius);
}

为ShapeButton 实现ShapeModeView接口:

public class ShapeButton extends AppCompatButton implements ShadowView, ShapeModelView {
//.....

    private static int[] elevationIds = new int[]{
            R.styleable.shape_button_carbon_elevation,
            R.styleable.shape_button_carbon_elevationShadowColor,
            R.styleable.shape_button_carbon_elevationAmbientShadowColor,
            R.styleable.shape_button_carbon_elevationSpotShadowColor
    };
    
    private static int[] cornerCutRadiusIds = new int[]{
            R.styleable.shape_button_carbon_cornerRadiusTopStart,
            R.styleable.shape_button_carbon_cornerRadiusTopEnd,
            R.styleable.shape_button_carbon_cornerRadiusBottomStart,
            R.styleable.shape_button_carbon_cornerRadiusBottomEnd,
            R.styleable.shape_button_carbon_cornerRadius,
            R.styleable.shape_button_carbon_cornerCutTopStart,
            R.styleable.shape_button_carbon_cornerCutTopEnd,
            R.styleable.shape_button_carbon_cornerCutBottomStart,
            R.styleable.shape_button_carbon_cornerCutBottomEnd,
            R.styleable.shape_button_carbon_cornerCut
    };

    private void initButton(AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.shape_button, defStyleAttr, defStyleRes);
        // 初始化阴影相关属性
        Carbon.initElevation(this, a, elevationIds);
        // 初始化圆角相关属性
        Carbon.initCornerCutRadius(this,a,cornerCutRadiusIds);
        a.recycle();
    }

 // -------------------------------
    // shadow
    // -------------------------------
    .....



// -------------------------------
    // shape
    // -------------------------------
    private ShapeAppearanceModel shapeModel = new ShapeAppearanceModel();
    private MaterialShapeDrawable shadowDrawable = new MaterialShapeDrawable(shapeModel);
    @Override
    public void setShapeModel(ShapeAppearanceModel shapeModel) {
     this.shapeModel = shapeModel;
        shadowDrawable = new MaterialShapeDrawable(shapeModel);
        if (getWidth() > 0 && getHeight() > 0)
            updateCorners();
        if (!Carbon.IS_LOLLIPOP_OR_HIGHER)
            postInvalidate();
    }

// View的轮廓形状
    private RectF boundsRect = new RectF();
    // View的轮廓形状形成的Path路径
    private Path cornersMask = new Path();
	
    /**
     * 更新圆角
     */
    private void updateCorners() {
        if (Carbon.IS_LOLLIPOP_OR_HIGHER) {
            // 如果不是矩形,裁剪View的轮廓
            if (!Carbon.isShapeRect(shapeModel, boundsRect)){
                setClipToOutline(true);
            }
            //该方法返回一个Outline对象,它描述了该视图的形状。
            setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    if (Carbon.isShapeRect(shapeModel, boundsRect)) {
                        outline.setRect(0, 0, getWidth(), getHeight());
                    } else {
                        shadowDrawable.setBounds(0, 0, getWidth(), getHeight());
                        shadowDrawable.setShadowCompatibilityMode(MaterialShapeDrawable.SHADOW_COMPAT_MODE_NEVER);
                        shadowDrawable.getOutline(outline);
                    }
                }
            });
        }
        // 拿到圆角矩形的形状
        boundsRect.set(shadowDrawable.getBounds());
        // 拿到圆角矩形的Path
        shadowDrawable.getPathForSize(getWidth(), getHeight(), cornersMask);
    }

    @Override
    public ShapeAppearanceModel getShapeModel() {
        return this.shapeModel;
    }

    @Override
    public void setCornerCut(float cornerCut) {
        shapeModel = ShapeAppearanceModel.builder().setAllCorners(new CutCornerTreatment(cornerCut)).build();
        setShapeModel(shapeModel);
    }

    @Override
    public void setCornerRadius(float cornerRadius) {
        shapeModel = ShapeAppearanceModel.builder().setAllCorners(new RoundedCornerTreatment(cornerRadius)).build();
        setShapeModel(shapeModel);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (!changed)
            return;

        if (getWidth() == 0 || getHeight() == 0)
            return;

        updateCorners();

    }

}

绘制轮廓

@Override
    public void draw(Canvas canvas) {
        boolean c = !Carbon.isShapeRect(shapeModel, boundsRect);

        if (Carbon.IS_PIE_OR_HIGHER) {
            if (spotShadowColor != null)
                super.setOutlineSpotShadowColor(spotShadowColor.getColorForState(getDrawableState(), spotShadowColor.getDefaultColor()));
            if (ambientShadowColor != null)
                super.setOutlineAmbientShadowColor(ambientShadowColor.getColorForState(getDrawableState(), ambientShadowColor.getDefaultColor()));
        }

		// 判断如果不是圆角矩形,需要使用轮廓Path,重新绘制一下Path,不然显示会很奇怪
        if (getWidth() > 0 && getHeight() > 0 && ((c && !Carbon.IS_LOLLIPOP_OR_HIGHER) || !shapeModel.isRoundRect(boundsRect))) {
            int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
            super.draw(canvas);
            paint.setXfermode(Carbon.CLEAR_MODE);
            if (c) {
                cornersMask.setFillType(Path.FillType.INVERSE_WINDING);
                canvas.drawPath(cornersMask, paint);
            }
            canvas.restoreToCount(saveCount);
            paint.setXfermode(null);
        }else{
            super.draw(canvas);
        }
    }

在Carbon中添加方法:


    public static void initCornerCutRadius(ShapeModelView shapeModelView, TypedArray a, int[] ids) {
        int carbon_cornerRadiusTopStart = ids[0];
        int carbon_cornerRadiusTopEnd = ids[1];
        int carbon_cornerRadiusBottomStart = ids[2];
        int carbon_cornerRadiusBottomEnd = ids[3];
        int carbon_cornerRadius = ids[4];
        int carbon_cornerCutTopStart = ids[5];
        int carbon_cornerCutTopEnd = ids[6];
        int carbon_cornerCutBottomStart = ids[7];
        int carbon_cornerCutBottomEnd = ids[8];
        int carbon_cornerCut = ids[9];

        float cornerRadius = Math.max(a.getDimension(carbon_cornerRadius, 0), 0.1f);
        float cornerRadiusTopStart = a.getDimension(carbon_cornerRadiusTopStart, cornerRadius);
        float cornerRadiusTopEnd = a.getDimension(carbon_cornerRadiusTopEnd, cornerRadius);
        float cornerRadiusBottomStart = a.getDimension(carbon_cornerRadiusBottomStart, cornerRadius);
        float cornerRadiusBottomEnd = a.getDimension(carbon_cornerRadiusBottomEnd, cornerRadius);
        float cornerCut = a.getDimension(carbon_cornerCut, 0);
        float cornerCutTopStart = a.getDimension(carbon_cornerCutTopStart, cornerCut);
        float cornerCutTopEnd = a.getDimension(carbon_cornerCutTopEnd, cornerCut);
        float cornerCutBottomStart = a.getDimension(carbon_cornerCutBottomStart, cornerCut);
        float cornerCutBottomEnd = a.getDimension(carbon_cornerCutBottomEnd, cornerCut);
        ShapeAppearanceModel model = ShapeAppearanceModel.builder()
                .setTopLeftCorner(cornerCutTopStart >= cornerRadiusTopStart ? new CutCornerTreatment(cornerCutTopStart) : new RoundedCornerTreatment(cornerRadiusTopStart))
                .setTopRightCorner(cornerCutTopEnd >= cornerRadiusTopEnd ? new CutCornerTreatment(cornerCutTopEnd) : new RoundedCornerTreatment(cornerRadiusTopEnd))
                .setBottomLeftCorner(cornerCutBottomStart >= cornerRadiusBottomStart ? new CutCornerTreatment(cornerCutBottomStart) : new RoundedCornerTreatment(cornerRadiusBottomStart))
                .setBottomRightCorner(cornerCutBottomEnd >= cornerRadiusBottomEnd ? new CutCornerTreatment(cornerCutBottomEnd) : new RoundedCornerTreatment(cornerRadiusBottomEnd))
                .build();
        shapeModelView.setShapeModel(model);
    }

    public static boolean isShapeRect(ShapeAppearanceModel model, RectF bounds) {
        return model.getTopLeftCornerSize().getCornerSize(bounds) <= 0.2f &&
                model.getTopRightCornerSize().getCornerSize(bounds) <= 0.2f &&
                model.getBottomLeftCornerSize().getCornerSize(bounds) <= 0.2f &&
                model.getBottomRightCornerSize().getCornerSize(bounds) <= 0.2f;
    }

使用

        <com.chinatsp.demo1.shadow.ShapeButton
            android:id="@+id/show_dialog_btn"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:layout_margin="@dimen/carbon_padding"
            android:background="#ffffff"
            android:stateListAnimator="@null"
            android:text="TOM"
            app:carbon_cornerRadius="10dp"
            android:elevation="2dp"
            app:carbon_elevationShadowColor="@color/carbon_red_700" />

        <com.chinatsp.demo1.shadow.ShapeButton
            android:id="@+id/show_date_dialog_btn"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:layout_margin="@dimen/carbon_padding"
            android:background="#ffffff"
            android:stateListAnimator="@null"
            android:text="TOM"
            app:carbon_cornerCut="10dp"
            android:elevation="10dp"
            app:carbon_elevationShadowColor="@color/carbon_grey_700" />

完整代码:


public class ShapeButton extends AppCompatButton implements ShadowView, ShapeModelView {
    public ShapeButton(@NonNull Context context) {
        super(context);
        initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);
    }

    public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initButton(attrs, android.R.attr.buttonStyle, R.style.carbon_Button);
    }

    public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initButton(attrs, defStyleAttr, R.style.carbon_Button);
    }

    public ShapeButton(Context context, String text, OnClickListener listener) {
        super(context);
        initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);
        setText(text);
        setOnClickListener(listener);
    }

    private static int[] elevationIds = new int[]{
            R.styleable.shape_button_carbon_elevation,
            R.styleable.shape_button_carbon_elevationShadowColor,
            R.styleable.shape_button_carbon_elevationAmbientShadowColor,
            R.styleable.shape_button_carbon_elevationSpotShadowColor
    };

    private static int[] cornerCutRadiusIds = new int[]{
            R.styleable.shape_button_carbon_cornerRadiusTopStart,
            R.styleable.shape_button_carbon_cornerRadiusTopEnd,
            R.styleable.shape_button_carbon_cornerRadiusBottomStart,
            R.styleable.shape_button_carbon_cornerRadiusBottomEnd,
            R.styleable.shape_button_carbon_cornerRadius,
            R.styleable.shape_button_carbon_cornerCutTopStart,
            R.styleable.shape_button_carbon_cornerCutTopEnd,
            R.styleable.shape_button_carbon_cornerCutBottomStart,
            R.styleable.shape_button_carbon_cornerCutBottomEnd,
            R.styleable.shape_button_carbon_cornerCut
    };

    protected TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

    private void initButton(AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.shape_button, defStyleAttr, defStyleRes);
        Carbon.initElevation(this, a, elevationIds);
        Carbon.initCornerCutRadius(this,a,cornerCutRadiusIds);
        a.recycle();
    }



    // -------------------------------
    // shadow
    // -------------------------------
    private float elevation = 0;
    private float translationZ = 0;
    private ColorStateList ambientShadowColor, spotShadowColor;
    @Override
    public float getElevation() {
        return elevation;
    }

    @Override
    public void setElevation(float elevation) {
        if (Carbon.IS_PIE_OR_HIGHER) {
            super.setElevation(elevation);
            super.setTranslationZ(translationZ);
        } else if (Carbon.IS_LOLLIPOP_OR_HIGHER) {
            if (ambientShadowColor == null || spotShadowColor == null) {
                super.setElevation(elevation);
                super.setTranslationZ(translationZ);
            } else {
                super.setElevation(0);
                super.setTranslationZ(0);
            }
        } else if (elevation != this.elevation && getParent() != null) {
            ((View) getParent()).postInvalidate();
        }
        this.elevation = elevation;
    }

    @Override
    public float getTranslationZ() {
        return translationZ;
    }

    public void setTranslationZ(float translationZ) {
        if (translationZ == this.translationZ)
            return;
        if (Carbon.IS_PIE_OR_HIGHER) {
            super.setTranslationZ(translationZ);
        } else if (Carbon.IS_LOLLIPOP_OR_HIGHER) {
            if (ambientShadowColor == null || spotShadowColor == null) {
                super.setTranslationZ(translationZ);
            } else {
                super.setTranslationZ(0);
            }
        } else if (translationZ != this.translationZ && getParent() != null) {
            ((View) getParent()).postInvalidate();
        }
        this.translationZ = translationZ;
    }

    @Override
    public ColorStateList getElevationShadowColor() {
        return ambientShadowColor;
    }

    @Override
    public void setElevationShadowColor(ColorStateList shadowColor) {
        ambientShadowColor = spotShadowColor = shadowColor;
        setElevation(elevation);
        setTranslationZ(translationZ);
    }

    @Override
    public void setElevationShadowColor(int color) {
        ambientShadowColor = spotShadowColor = ColorStateList.valueOf(color);
        setElevation(elevation);
        setTranslationZ(translationZ);
    }

    @Override
    public void setOutlineAmbientShadowColor(ColorStateList color) {
        ambientShadowColor = color;
        if (Carbon.IS_PIE_OR_HIGHER) {
            super.setOutlineAmbientShadowColor(color.getColorForState(getDrawableState(), color.getDefaultColor()));
        } else {
            setElevation(elevation);
            setTranslationZ(translationZ);
        }
    }

    @Override
    public void setOutlineAmbientShadowColor(int color) {
        setOutlineAmbientShadowColor(ColorStateList.valueOf(color));
    }

    @Override
    public int getOutlineAmbientShadowColor() {
        return ambientShadowColor.getDefaultColor();
    }

    @Override
    public void setOutlineSpotShadowColor(int color) {
        setOutlineSpotShadowColor(ColorStateList.valueOf(color));
    }

    @Override
    public void setOutlineSpotShadowColor(ColorStateList color) {
        spotShadowColor = color;
        if (Carbon.IS_PIE_OR_HIGHER) {
            super.setOutlineSpotShadowColor(color.getColorForState(getDrawableState(), color.getDefaultColor()));
        } else {
            setElevation(elevation);
            setTranslationZ(translationZ);
        }

    }

    @Override
    public int getOutlineSpotShadowColor() {
        return ambientShadowColor.getDefaultColor();
    }

    @Override
    public void draw(Canvas canvas) {
        boolean c = !Carbon.isShapeRect(shapeModel, boundsRect);

        if (Carbon.IS_PIE_OR_HIGHER) {
            if (spotShadowColor != null)
                super.setOutlineSpotShadowColor(spotShadowColor.getColorForState(getDrawableState(), spotShadowColor.getDefaultColor()));
            if (ambientShadowColor != null)
                super.setOutlineAmbientShadowColor(ambientShadowColor.getColorForState(getDrawableState(), ambientShadowColor.getDefaultColor()));
        }

        // 判断如果不是圆角矩形,需要使用轮廓Path,绘制一下Path,不然显示会很奇怪
        if (getWidth() > 0 && getHeight() > 0 && ((c && !Carbon.IS_LOLLIPOP_OR_HIGHER) || !shapeModel.isRoundRect(boundsRect))) {
            int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
            super.draw(canvas);
            paint.setXfermode(Carbon.CLEAR_MODE);
            if (c) {
                cornersMask.setFillType(Path.FillType.INVERSE_WINDING);
                canvas.drawPath(cornersMask, paint);
            }
            canvas.restoreToCount(saveCount);
            paint.setXfermode(null);
        }else{
            super.draw(canvas);
        }
    }

    // -------------------------------
    // shape
    // -------------------------------
    private ShapeAppearanceModel shapeModel = new ShapeAppearanceModel();
    private MaterialShapeDrawable shadowDrawable = new MaterialShapeDrawable(shapeModel);
    @Override
    public void setShapeModel(ShapeAppearanceModel shapeModel) {
        this.shapeModel = shapeModel;
        shadowDrawable = new MaterialShapeDrawable(shapeModel);
        if (getWidth() > 0 && getHeight() > 0)
            updateCorners();
        if (!Carbon.IS_LOLLIPOP_OR_HIGHER)
            postInvalidate();
    }
    // View的轮廓形状
    private RectF boundsRect = new RectF();
    // View的轮廓形状形成的Path路径
    private Path cornersMask = new Path();

    /**
     * 更新圆角
     */
    private void updateCorners() {
        if (Carbon.IS_LOLLIPOP_OR_HIGHER) {
            // 如果不是矩形,裁剪View的轮廓
            if (!Carbon.isShapeRect(shapeModel, boundsRect)){
                setClipToOutline(true);
            }
            //该方法返回一个Outline对象,它描述了该视图的形状。
            setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    if (Carbon.isShapeRect(shapeModel, boundsRect)) {
                        outline.setRect(0, 0, getWidth(), getHeight());
                    } else {
                        shadowDrawable.setBounds(0, 0, getWidth(), getHeight());
                        shadowDrawable.setShadowCompatibilityMode(MaterialShapeDrawable.SHADOW_COMPAT_MODE_NEVER);
                        shadowDrawable.getOutline(outline);
                    }
                }
            });
        }
        // 拿到圆角矩形的形状
        boundsRect.set(shadowDrawable.getBounds());
        // 拿到圆角矩形的Path
        shadowDrawable.getPathForSize(getWidth(), getHeight(), cornersMask);
    }

    @Override
    public ShapeAppearanceModel getShapeModel() {
        return this.shapeModel;
    }

    @Override
    public void setCornerCut(float cornerCut) {
        shapeModel = ShapeAppearanceModel.builder().setAllCorners(new CutCornerTreatment(cornerCut)).build();
        setShapeModel(shapeModel);
    }

    @Override
    public void setCornerRadius(float cornerRadius) {
        shapeModel = ShapeAppearanceModel.builder().setAllCorners(new RoundedCornerTreatment(cornerRadius)).build();
        setShapeModel(shapeModel);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (!changed)
            return;

        if (getWidth() == 0 || getHeight() == 0)
            return;

        updateCorners();

    }
}

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

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

相关文章

【软考设计师】S01 数据结构 E01 线性结构 P01 线性表

线性表 前言——线性结构线性表线性表的定义线性表的特点线性表的存储结构顺序存储链式存储单链表双向链表循环链表静态链表 前言——线性结构 线性结构是一种基本的数据结构&#xff0c;主要用于对客观世界中具有单一前驱和后继的数据关系进行描述。线性结构的特点是数据元素…

漏刻有时数据可视化Echarts组件开发(43)水球图svg温度计动画

SVG是一种用XML定义的语言&#xff0c;用来描述二维矢量及矢量/栅格图形。具体来说&#xff0c;SVG图形是可伸缩的矢量图形&#xff0c;其图像质量不会因放大或改变尺寸而损失。 在SVG中&#xff0c;可以创建和修改图像、对图像进行搜索和索引、对其进行脚本化或压缩。此外&am…

【网络安全入门】学习网络安全必须知道的100 个网络基础知识

前言 话不多说&#xff0c;完整的资料已经上传至CSDN官方&#xff0c;需要的可以点击链接自取【282G】网络安全&黑客技术零基础到进阶全套学习大礼包&#xff0c;免费分享&#xff01; 1 什么是链接? 链接是指两个设备之间的连接。它包括用于一个设备能够与另一个设备…

Zabbix“专家坐诊”第206期问答汇总

问题一 Q&#xff1a;老师&#xff0c;我想配置一下监控项和触发器&#xff0c;目前我想要三个&#xff0c;内存的使用情况百分比、磁盘的剩余多少G、CPU的使用情况百分比&#xff0c;用自带的模板修改&#xff0c;该怎么做&#xff1f; A&#xff1a;可以用100减去内置键值cp…

ICCV 2023 | 当尺度感知调制遇上Transformer,会碰撞出怎样的火花?

作者 &#xff5c; AFzzz 1 文章介绍 近年来&#xff0c;基于Transformer和CNN的视觉基础模型取得巨大成功。有许多研究进一步地将Transformer结构与CNN架构结合&#xff0c;设计出了更为高效的hybrid CNN-Transformer Network&#xff0c;但它们的精度仍然不尽如意。本文介绍…

java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

基于ssm的少儿编程网上报名系统+vue【附PPT|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; 注册用户&#xff1a;用户名、密码、姓名、联系电话 用户&#xff1a; ①首页、课程信息推荐、课程资讯、查看更多 ②课程详情、点我收藏、购买、评论、留言反馈 ③个人中心、修改用户名、密码、姓名、性别、头像、手机号、我的收藏等 后台登录…

Pycharm调试时,到达断点后,一直connected

Pycharm调试时&#xff0c;到达断点后&#xff0c;一直connected&#xff0c;画了一上午时间&#xff0c;最后发现是因为我dataloader使用的是多进程&#xff0c; 选中Gevent兼容后解决。

九方云学堂学员告诉你学习可以掌握哪些内容

在当前的股票市场环境下,存在许多不确定性因素和风险。虽然不少新兴行业的诞生,为投资者带来了更多的投资机会,但是风险同样会与日俱增。在这种情况下,作为一名投资者,想要在不断变化的市场环境中,提高投资胜率,做到复利,完整、科学的投资策略,成为了越来越多投资者关注的焦点。…

软信天成:物料主数据的标准管理

在制造企业加工生产的过程中&#xff0c;物料管理尤为重要。严格的原料管控将直接影响产品的品质、工作效率以及制造成本。相较于其他主数据&#xff0c;物料主数据是一种最复杂、数据量最大也是最关键的主数据&#xff0c;其准确性和规范程度将直接决定系统是否顺畅运行。 因此…

Python教程:方法重载

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 方法重载 方法重载在Python中起着关键作用。 方法有时接受零参数&#xff0c;有时接受一个或多个参数。 当我们以不同的方式调用同一个方法时&#xff0c;这就被称为方法…

Windows mysql 5.7 msi版、mysql 8.0 msi版下载、安装教程,附详细图文

大家好&#xff0c;今天为大家带来的是 mysql 5.7 msi &#xff0c; MySql 8.0 版本的下载、安装教程&#xff0c;附详细图文。本文以 5.7 版本为例子&#xff0c;帮助大家讲解。希望对大家有所帮助 文章首发地址 一、下载地址 这里提供一下 CSDN 镜像下载地址&#xff0c;有…

ESP-07S进行TCP 通信测试

一&#xff0c;TCP Server 为 AP 模式&#xff0c;TCP Client 为 Station 模式。 这里电脑pc作为TCP Server&#xff0c;ESP-07S作为TCP Client 。 二&#xff0c;电脑端配置。 1&#xff0c;开启热点。 2&#xff0c;转到“设置”&#xff0c;编辑热点信息。 3&#xff0c;关闭…

ROS2 Galactic安装

ROS2 Galactic安装 ROS2 Galactic安装字体编码检查添加ros2仓库到本机安装ROS2系统测试ROS卸载ros2 ROS2 Galactic安装 字体编码检查 安装需要设置本级为UTF-8字体&#xff0c;使用如下指令检查&#xff1a; locale # check for UTF-8sudo apt update && sudo apt …

【C++】空间配置器 allocator:原理及底层解析

文章目录 空间配置器一级空间配置器二级空间配置器1. 内存池2. SGI-STL中二级空间配置器设计 - - 哈希桶3. 二级空间配置器的空间申请 空间配置器的默认选择空间配置器的在封装&#xff1a;添加了数据类型大小空间配置器对象的构造与析构 容器中的 allocator 空间配置器 提到空…

移动办公管理系统低代码解决方案

随着企业数字化转型的加速&#xff0c;人工智能、云计算、大数据等技术应用的愈加广泛&#xff0c;数字化的办公系统在企事业内部编织起一套高效、畅通的信息互联体系&#xff0c;极大推动了企事业单位生产力的发展。 但与此同时&#xff0c;由于需要依赖固定的办公场所和固定…

最值得收藏的顶级专业数据恢复软件列表 [持续更新]

互联网上充斥着很多的数据恢复软件&#xff0c;每个软件都声称自己是最好的。现在该同意谁的观点呢&#xff1f;我们创建了 2023 年顶级专业数据恢复软件列表。下载顶级一流数据恢复专业软件的免费试用版&#xff0c;我们强烈建议用户评估演示版本&#xff0c;然后选择付费版本…

Python 樱花

Python实现樱花 效果图 &#xff08;源码在下面&#xff09; 源码&#xff1a; from turtle import * from random import * from math import *def tree(n, l):pd() # 下笔# 阴影效果t cos(radians(heading() 45)) / 8 0.25pencolor(t, t, t)pensize(n / 3)forward(l…

面试经典 150 题 1 —(数组 / 字符串)— 88. 合并两个有序数组

88. 合并两个有序数组 方法一&#xff1a; class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {for(int i 0; i<n;i){nums1[mi] nums2[i];}sort(nums1.begin(),nums1.end());} };方法二&#xff1a; clas…

CRMEB 标准版商城系统新增主题风格颜色【超级完整教程】

一、后台 1.新增主题图片 assets/images/brown.jpg和assets/images/brownsign.png 2.修改admin/src/pages/setting/themeStyle/index.vue 3.修改admin/src/pages/marketing/sign/index.vue 4.修改admin/src/pages/system/group/visualization.vue &#xff08;第三步和第四步…