Android自定义控件

news2024/11/26 14:58:45

目录

  • Android自定义控件
    • 一、对现有控件进行扩展
    • 二、创建复合控件
      • 1 定义属性
      • 2 组合控件
      • 3 引用UI模板
    • 三、重写View来实现全新控件
      • 1 弧线展示图
        • 1.1 具体步骤:
      • 2 音频条形图
        • 2.1 具体步骤
    • 四、补充:自定义ViewGroup

Android自定义控件

ref:

Android自定义控件 - 掘金 (juejin.cn)

自定义视图组件 | Android 开发者 | Android Developers (google.cn)

当系统控件不能满足我们的需求的时候,这时候我们就需要自定义控件,根据我们的需求来定制一个能满足我们需求的控件。

如果预构建的微件或布局都不能满足您的需求,您可以创建自己的 View 子类。如果您只需要对现有微件或布局进行细微调整,则只需将相应微件或布局子类化并替换其方法即可。

在自定义View时,通常会重写onDraw()方法来绘制View的显示内容。

如果该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法。

通过自定义attrs属性,还可以设置新的属性配置值。

自定义View的时候,并不需要重写所有的方法,只需要重写特定条件的回调方法即可。

在View中通常有以下一些比较重要的回调方法:

  • onFinishInflate():从XML加载组件后回调。
  • onSizeChanged():组件大小改变时回调。
  • onMeasure():回调该方法来进行测量。
  • onLayout():回调该方法来确定显示的位置。
  • onTouchEvent():监听到触摸事件时回调。

在通常情况下,有三种方法来实现自定义的控件:

  • 对现有控件进行拓展
  • 创建复合控件
  • 重写View来实现全新控件

一、对现有控件进行扩展

在原生控件的基础上进行拓展,增加新的功能、修改显示的UI等

二、创建复合控件

继承一个合适的ViewGroup,再给它添加指定功能的控件,从而组合成新的复合控件,创建出具体重用功能的控件集合

以一个通用的TopBar为示例

public class TopBar extends RelativeLayout {

    public TopBar(Context context) {
        this.TopBar(context, null);
    }

    public TopBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 初始化的方法
        // 初始化属性
        initAttr(context, attrs)
        // 初始化布局
        initView(context);
        // 初如化事件
        initEvent();
    }

}

1 定义属性

为一个View提供可自定义的属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件,并在该文件中通过如下代码定义相应的属性即可。

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <declare-styleable name="TopBar">   <!-- 确定引用的名称 -->
        <!-- 定义title文字,大小,颜色 -->
        <attr name="title" format="string" />  <!-- attr 标签来声明具体的自定义属性,name声明属性名,format来指定属性的类型 -->
        <attr name="titleTextSize" format="dimension" />
        <attr name="titleTextColor" format="color" />
        <!-- 定义left 文字,大小,颜色,背景 -->
        <attr name="leftTextColor" format="color" />
        <attr name="leftTextSize" format="dimension" />
        <!-- 表示背景可以是颜色,也可以是引用 -->
        <attr name="leftBackground" format="reference|color" />
        <attr name="leftText" format="string" />
        <!-- 定义right 文字,大小,颜色,背景 -->
        <attr name="rightTextColor" format="color" />
        <attr name="rightTextSize" format="dimension"/>
        <attr name="rightBackground" format="reference|color" />  <!--  有些属性可以是颜色属性,也可以是引用属性。比如按键的背景,所以使用“|”来分隔不同的属性 -->
        <attr name="rightText" format="string" />
    </declare-styleable>

</resources>

// 在TopBar的构造方法中,通过如下所示代码来获取在XML布局文件中自定义的那些属性,即与我们使用系统提供的那些属性一样。
// TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);

系统提供TypedArray来获取自定义属性集,后面引用的styleable的TopBar,就是在XML中通过所指定的name名。通过TypeArray对象的getString()、getColor()等方法,就可以获取这些定义的属性值。

需要注意的是,当获取完所有的属性值后,需要调用TypedArray的recyle()方法来完成资源的回收。

public class TopBar extends RelativeLayout {

    private int mLeftTextColor;
    private Drawable mLeftBackground;
    private String mLeftText;
    private float mLeftTextSize;

    private int mRightTextColor;
    private Drawable mRightBackground;
    private String mRightTextSize;
    private float mRightTextSize;

    private String mTitleText;
    private float mTitleTextSize;
    private int mTitleTextColor;

    private void initAttr(Context context, AttributeSet attrs) {
        // 通过这个方法,将你在attrs.xml中定义的declare-styleable的所有属性的值存储到TypedArray.
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
        // 从TypedArray中取出对应的值来为要设置的属性赋值
        mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
        mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
        mLeftText = ta.getString(R.styleable.TopBar_leftText);
        mLeftTextSize = typed.getDimension(R.styleable.TitleBar_leftTextSize, 20);

        mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
        mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);
        mRightText = ta.getString(R.styleable.TopBar_rightText);
        mRightTextSize = typed.getDimension(R.styleable.TitleBar_rightTextSize, 20);

        mTitleText = ta.getString(R.styleable.TopBar_titleText);
        mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);
        mTitleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor, 0);

    	// 获取完TypedArray的值后,一般要调用recyle()方法来避免重新创建的时候的错误
    	ta.recycle();
    }

    public TopBar(Context context) {
        this.TopBar(context, null);
    }

    public TopBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 初始化的方法
        // 初始化属性
        initAttr(context, attrs)
        // 初始化布局
        initView(context);
        // 初如化事件
        initEvent();
    }

}

2 组合控件

TopBar由三个控件组成,左边按钮mLeftButton、右边按钮mRightButton、中间标题栏mTitleView。

通过动态添加控件的方式,使用addView()方法将三个控件加入到定义的TopBar模板中,并给它们设置我们前面所获取到的具体的属性值,比如标题的文字、颜色、大小等,代码如下所示。

private TextView mTitleView;
private Button mLeftButton;
private Button mRightButton;

private RelativeLayout.LayoutParams mLeftParams;
private RelativeLayout.LayoutParams mRightParams;
private RelativeLayout.LayoutParams mTitleParams;

private void initView(Context context) {
    mTitleView = new TextView(context);
    mLeftButton = new Button(context);
    mRightButton = new Button(context);

    // 为创建的组件赋值,值就来源于引用的xml文件中给对应属性的赋值
    mTitleView.setText(mTitleText);
    mTitleView.setTextSize(mTitleTextSize);
    mTitleView.setTextColor(mTitleTextColor);
    mTitleView.setGravity(Gravity.CENTER);

    mLeftButton.setText(mLeftText);
    mLeftButton.setTextColor(mLeftTextColor);
    mLeftButton.setBackgroundDrawable(mLeftBackground);
    mLeftButton.setTextSize(mLeftTextSize);

    mRightButton.setText(mRightText);
    mRightButton.setTextSize(mRightTextSize);
    mRightButton.setBackgroundDrawable(mRightBackground);
    mRightButton.setTextColor(mRightTextColor);

    // 为组件元素设置相应的布局元素
    // 设置布局的layout_width和layout_height属性
    mLeftParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    // 该方法表示所设置节点的属性必须关联其他兄弟节点或者属性值为布尔值。
    mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
    // 动态添加组件
    addView(mLeftButton, mLeftParams);

    mRightParams= new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
    addView(mRightButton, mRightParams);

    mTitleParams= new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    mTitleParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
    addView(mTitleView, mTitleParams);
}

作为UI模板,调用者所需要这些按钮的实现功能都是不一样的。

因此,不能直接在UI模板里实现逻辑,可以通过接口回调的思想,实现逻辑交给调用者。

  • 定义接口。定义一个左右按钮点击的接口,并创建两个方法,分别用于左右两个按钮的点击

    • // 在类内部定义一个接口对象,实现回调机制,不用去考虑如何实现,具体实现由调用者去创建
      public interface OnClickListener{
          // 左按钮点击事件
          void leftClick();
          // 右按钮点击事件
          void rightClick();
      }
      
  • 暴露接口给调用者。在模板方法中,为左右按键增加点击事件,但不实现具体逻辑,而是调用接口中相应的点击方法

    • // 创建一个接口对象
      private OnClickListener mListener;
      
      // 暴露一个方法给调用者来注册接口,通过接口来获得回调者对接口方法的实现
      public void setOnClickListener(OnClickListener listener) {
          this.mListener = listener;
      }
      
      private void initEvent(){
          // 按钮的点击事件,不需要具体的实现,只需要调用接口方法,回调的时候会有具体实现
          mLeftButton.setOnClickListener(new OnClickListener() {
              @Override
              public void onClick(View v) {
                  mListener.leftClick();
              }
          });
      
          mRightButton.setOnClickListener(new OnClickListener() {
              @Override
              public void onClick(View v) {
                  mListener.rightClick();
              }
          });
      }
      
      
  • 实现接口回调。调用者的代码实现这样接口,确定具体的实现逻辑,并使用第二步中暴露的方法,将接口的对象传递进去,从而完成回调。通常情况下,可以使用匿名内部类的形式来实现接口中的方法

    • mTopBar.setOnClickListener(new TopBar.OnClickListener() {
          @Override
          public void leftClick() {
              // 点击左边按钮
          }
      
          @Override
          public void rightClick() {
              // 点击右边按钮
          }
      }
      
      
  • 除了通过接口回调的方式来实现动态的控制UI模板,同样可以使用公共方法来动态地修改UI模板中的UI,进一步提高了模板的可定制性

    • public static final int LEFT = 1;
      public static final int RIGHT = 2;
      
      /**
        * 设置按钮的显示与否通过常量区分,visible区分是否显示
        *
        * @param view  标记View
        * @param visible  是否显示
        * /
      public void setVisable(int view, int visible){
          switch(view) {
              case LEFT:
                  mLeftButton.setVisibility(visible);
              break;
              case RIGHT:
                  mRightButton.setVisibility(visible);
              break;
          }
      }
      
    • 通过如上代码,调用者通过TopBar对象调用这个方法后,根据参数,可以动态地控制按钮的显示

      • // 控制TopBar上组件的状态
        mTopBar.setVisable(TopBar.LEFT, View.VISIBLE);
        mTopBar.setVisable(TopBar.RIGHT, View.GONE);
        
        

3 引用UI模板

在引用前,需要指定引用第三方控件的名字空间

xmlns:android="http://schemas.android.com/apk/res/android"

<!-- 
这里指定了名字空间为“android”,因此在接下来使用系统属性时,才可以使用“android:”来引用Android的系统属性。
同样,如果要使用自定义属性,那么就需要创建自己的名字空间。
在Android Stuido中,第三方控件都使用如下代码来引用名字空间。
xmlns:app="http://schemas.android.com/apk/res/res-auto"   (将引入的第三方控件的名字空间取名为app)

在XML文件中使用自定义的属性时,就可以通过这个名字空间来引用,如下
-->

<com.example.demo.TopBar
        android:id="@+id/tb"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_alignParentBottom="true"
        app:leftBackGround="#ff000000"
        app:leftText="Back"
        app:leftTextColor="#ffff6734"
        app:leftTextSize="25dp" 
        app:rightText="More"
        app:rightTextSize="25dp"
        app:rightTextColor="#ff123456"
        app:title="自定义标题"
        app:titleTextColor="#ff654321"/>

使用自定义的View与系统原生的View最大的区别就是在声明控件时,需要指定完整的包名,而在引用自定义的属性时,需要使用自定义的xmlns名字。

三、重写View来实现全新控件

Android系统原生控件无法满足我们的需求的时候,我们就可以完全创建一个新的自定义View来实现需要的功能。

  • 创建一个自定义View,难点在于绘制控件和实现交互,这也是评价一个自定义View优劣的标准之一
  • 需要继承View类,并重写它的onDraw()onMeasure()等方法来实现绘制逻辑
  • (可选) 重写onTouchEvent()等触控事件来实现交互逻辑
  • (可选) 引入自定义属性,丰富自定义View的可定制性

1 弧线展示图

实例:

1.1 具体步骤:

(1)绘制中间的圆形

(2)绘制圆形中间的文字

(3)绘制圆形外面的圆弧、外圈的弧线

public class ScaleMap extends View {

    private int mMeasureHeigth;// 控件高度
    private int mMeasureWidth;// 控件宽度
    // 圆形
    private Paint mCirclePaint;
    private float mCircleXY;//圆心坐标
    private float mRadius;//圆形半径
    // 圆弧
    private Paint mArcPaint;
    private RectF mArcRectF;//圆弧的外切矩形
    private float mSweepAngle;//圆弧的角度
    private float mSweepValue;
    // 文字
    private Paint mTextPaint;
    private String mShowText;//文本内容
    private float mShowTextSize;//文本大小

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

    public ScaleMap(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScaleMap(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }
    
    // 如果不用后面的参数,就不需要重构后面的,直接将其内容写在第一个构造方法就可以,父类会自动执行后面的构造方法
    public ScaleMap(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        // 初始化操作  
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec);//获取控件宽度
        mMeasureHeigth = MeasureSpec.getSize(heightMeasureSpec);//获取控件高度
        setMeasuredDimension(mMeasureWidth, mMeasureHeigth);

        initPaint();  // 画笔中用到了宽高所以在此初始化画笔
    }

    /**
    * 准备画笔,-->  在初始化的时候,设置好绘制三种图形的参数
    */
    private void initPaint() {
        float length = Math.min(mMeasureWidth,mMeasureHeigth);
        // 圆的代码
        mCircleXY = length / 2;// 确定圆心坐标
        mRadius = (float) (length * 0.5 / 2);// 确定半径
        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);// 去锯齿
        mCirclePaint.setColor(getResources().getColor(android.R.color.holo_green_dark));

        // 弧线,需要 指定其椭圆的外接矩形
        // 矩形
        mArcRectF = new RectF((float) (length * 0.1), (float) (length * 0.1), (float)(length * 0.9),(float) (length * 0.9));
        mSweepAngle = (mSweepValue / 100f) * 360f;
        mArcPaint = new Paint();
        mArcPaint.setColor(getResources().getColor(android.R.color.holo_blue_bright));
        mArcPaint.setStrokeWidth((float) (length * 0.1));//圆弧宽度
        mArcPaint.setStyle(Style.STROKE);//圆弧
        // 文字,只需要设置好文字的起始绘制位置即可
        mShowText = "Android Skill";
        mShowTextSize = 50;
        mTextPaint = new Paint();
        mTextPaint.setTextSize(mShowTextSize);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    protected void onDraw(Canvas canvas) { // --> 在onDraw()方法中去绘制
        super.onDraw(canvas);
        // 绘制圆
        canvas.drawCircle(mCircleXY, mCircleXY, mRadius, mCirclePaint);
        // 绘制圆弧,逆时针绘制,角度跟
        canvas.drawArc(mArcRectF, 90, mSweepAngle, false, mArcPaint);
        // 绘制文字
        canvas.drawText(mShowText, 0, mShowText.length(), mCircleXY, mCircleXY + mShowTextSize / 4, mTextPaint);
    }

    // 让调用者来设置不同的状态值,使弧形弧度变化
    public void setSweepValue(float sweepValue) {
        if (sweepValue != 0) {
            mSweepValue = sweepValue;
        } else {
            mSweepValue = 25;
        }
        // 这个方法可以刷新UI  -->  在修改UI后通过调用this.invalidate()方法来实现UI的重绘
        this.invalidate();
    }

}

2 音频条形图

实例:

2.1 具体步骤

(1)基本思路:绘制一个个的矩形,每个矩形之间稍微偏移一点距离即可

动态效果实现思路:在onDraw()方法中调用invalidate()方法通知View进行重绘

​ --> 问题:这样直接重绘的速度太快,影响观感效果体验,因此可以适当进行延时通知重绘:

​ 使用postInvalidateDelayed(300/*ms*/)来进行延时重绘

this.invalidate();
this.postInvalidateDelayed(300);

(2)矩形渐变效果

思路:给绘制的Paint对象可以增加一个LinearGradient渐变效果

private int mWidth;//控件的宽度
private int mRectWidth;// 矩形的宽度
private int mRectHeight;// 矩形的高度
private Paint mPaint;
private int mRectCount;// 矩形的个数
private int offset = 5;// 偏移
private double mRandom;
private LinearGradient lg;// 渐变

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

public ScaleMap(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    initPaint();  // 这些要在这里设置,因为渐变效果
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 设置宽高
    setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}

// 初始化画笔
private void initPaint() {
    mPaint = new Paint();
    mPaint.setColor(Color.GREEN);
    mPaint.setStyle(Paint.Style.FILL);
    mRectCount = 12;
}

//重写onDraw方法
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (int i = 0; i < mRectCount; i++) {
        mRandom = Math.random();
        float currentHeight = (int) (mRectHeight * mRandom);
        canvas.drawRect((float) (mWidth * 0.4 / 2 + mRectWidth * i + offset * i), currentHeight,
        (float) (mWidth * 0.4 / 2 + mRectWidth * (i + 1) + offset * i), mRectHeight, mPaint);
    }
    postInvalidateDelayed(300);
}

//重写onSizeChanged方法,给画笔加上渐变
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = getWidth();
    mRectHeight = getHeight();
    mRectWidth = (int) (mWidth * 0.6 / mRectCount);
    lg = new LinearGradient(0, 0, mRectWidth, mRectHeight, Color.GREEN, Color.BLUE, TileMode.CLAMP);
    mPaint.setShader(lg);
}

四、补充:自定义ViewGroup

TODO

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

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

相关文章

Mac电脑录屏软件 Screen Recorder by Omi 中文最新

Screen Recorder by Omi是一款屏幕录制软件&#xff0c;它可以帮助用户轻松地录制屏幕活动&#xff0c;并将其保存为高质量的视频文件。 该软件提供了多种录制选项&#xff0c;包括全屏录制、选择区域录制和单窗口录制等&#xff0c;同时提供了丰富的设置选项&#xff0c;如视…

2023年显著性检测论文及代码汇总(4)

ACM MM Partitioned Saliency Ranking with Dense Pyramid Transformers code Abstacrt&#xff1a;显著性排序&#xff0c;其重点是评估实例级别的显著性程度。本文提出分区排序范式&#xff0c;该范式将无序的显著性实例分区&#xff0c;然后根据分区之间的相关性对其进行排…

[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法与软件开发模型

目录 一、软件开发方法&#xff1a;组织、管理、复用软件代码的方法 1.1 概述: 软件聚合的程度由简单到复杂 1.2 结构化的开发方法 1.3 面对对象的开发方法 1.4 面向组件的开发方法 1.5 面向服务的开发方法 1.6 不同开发方法比较&#xff1a;结构化、面对对象、面向组件…

ce从初阶到大牛--动态网络部署

1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! systemctl stop firewalld setenforce 0 cd /etc/httpd/conf.d/ vim openlab.conf ** <VirtualHost 192.168.170.100:80>DocumentRoot /www/openlabServerName 192.168.170.100 </VirtualHost>…

基础算法(排序、二分、精度运算)

这里写目录标题 排序快速排序主要思想解法其它细节 归并主要思想解法 STL - sort总结时间效率 二分整数二分主要思想解法举例&#xff1a;起始位置结束位置 浮点数二分解法 二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目…

Wnmp服务安装并结合内网穿透实现公网远程访问——“cpolar内网穿透”

文章目录 前言1.Wnmp下载安装2.Wnmp设置3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 WNMP是Windows系统下的绿色NginxMysqlPHP环境集成套件包&#xff0c;安装完成后即可得到一个Nginx MyS…

【公益案例展】 温州市人民检察院——公益诉讼智能研判预警应用案例

‍ 数澜科技公益案例 本项目案例由数澜科技投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2023中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 近年来&#xff0c;智慧检务已成大势所趋&#xff0c;《“…

【Linux】七、基础IO

预备知识 文件 属性&#xff08;本质上也是数据&#xff09;内容&#xff1b; 文件的所有操作大致有两种&#xff0c;对内容的操作&#xff0c;和对属性的操作&#xff1b; 文件在磁盘中放置&#xff0c;磁盘是硬件&#xff0c;只有操作系统可以真正的访问磁盘&#xff1b;C\C…

【Matplotlib】plt.plot() X轴横坐标展示完整整数坐标

比如说&#xff0c;我的数据应该是 x轴从2到21的20个整数 y轴对应值 但是直接plot的话x轴显示居然有小数点什么鬼 可以这样改

四维轻云如何实现地理空间数据在线管理、编辑及分享?

四维轻云是一款轻量化的地理空间数据网页管理平台&#xff0c;支持多种地理空间数据的在线管理、编辑及分享。现阶段&#xff0c;平台具有项目管理、数据上传、场景搭建、发布分享、团队成员、素材库等功能模块&#xff0c;支持项目团队成员在线协作管理&#xff0c;能够在线管…

Python---capitalize() 方法---把字符串的首字母大写,其他字符全部小写

capitalize 英 /ˈkpɪtəlaɪz/ v. 用大写字母书写&#xff08;或印刷&#xff09;&#xff0c;把……首字母大写&#xff1b;为&#xff08;开办或发展企业&#xff09;提供资金&#xff1b;&#xff08;将资产或股票&#xff09;变现&#xff0c;使资本化&#xff1b;&…

win11下使用VMmare设置CentOS7里面的静态IP

1&#xff0c;win11上的VMware 8 设置 2&#xff0c;选择VMmare上的虚拟网络编辑进行设置 #3&#xff0c;接下来进入虚拟机设置&#xff08;就是进入CentOS7 打开终端 右键 Open Terminal &#xff09; # 切换root su root #ksana #编辑网络配置文件 vi /etc/sysconfig/networ…

visual studio Python 配置QGIS(qgis)教程

visual studio Python 配置QGIS&#xff08;qgis&#xff09;教程 这个教程全网独一份啊&#xff0c;博主是自己摸索出来的。 visual studio Python 配置QGIS&#xff08;qgis&#xff09;环境一共分为两部&#xff1a; 第一步安装QGIS&#xff1a; 下载链接如下 https://www…

Java快速排序算法、三路快排(Java算法和数据结构总结笔记)[7/20]

一、什么是快速排序算法 快速排序的基本思想是选择一个基准元素&#xff08;通常选择最后一个元素&#xff09;将数组分割为两部分&#xff0c;一部分小于基准元素&#xff0c;一部分大于基准元素。 然后递归地对两部分进行排序&#xff0c;直到整个数组有序。这个过程通过 par…

数据的备份和恢复

数据的备份和恢复 备份&#xff1a;完全备份 增量备份 完全备份&#xff1a;将整个数据库完整的进行备份 增量备份&#xff1a;在完全备份的基础之上&#xff0c;对后续新增的内容进行备份 备份的需求 1、在生产环境中&#xff0c;数据的安全至关重要、任何数据的丢失都可…

【10套模拟】【2】

关键字&#xff1a; 哈希函数解决问题、进栈、无向图边与度、双向链表插入新结点、折半查找判定树ASL、孩子兄弟表示法、树变二叉、快排partiction划分

十大排序算法C++实现

分类 复杂度 排序稳定性定义&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#xff0c;这些记录的相对次序保持不变&#xff0c;即在原序列中&#xff0c;A1A2&#xff0c;且A1在A2之前&#xff0c;而在排序后的序…

Django初窥门径-oauth登录认证

引言 在现代Web应用程序中&#xff0c;用户身份验证和授权是至关重要的组成部分。Django&#xff0c;一个流行的Python Web框架&#xff0c;为用户身份验证提供了内置支持。本文将探讨如何创建和注册Django应用&#xff0c;自定义身份验证服务&#xff0c;配置AUTHENTICATION_…

网络数据包传感器简化流量监控

数据包捕获基于数据包镜像的概念&#xff0c;可用于深度数据包检查、测量应用程序的响应时间以及监视服务器、网络和用户行为&#xff0c;该技术还可用于对需要特定信息的某些区域进行广泛分析&#xff0c;尽管它有效&#xff0c;但并非在所有情况下都是必要的。要分析和管理流…

【MogDB/openGauss误删未归档的xlog日志如何解决】

在使用MogDB/openGauss数据库的过程中&#xff0c;有时候大量业务&#xff0c;或者导数据会导致pg_xlog下的日志数量持续增长&#xff0c;此时如果xlog的产生频率太快&#xff0c;而来不及自动清理&#xff0c;极有可能造成pg_xlog目录的打满。如果对数据库的xlog不太了解的时候…