• Android9 MTK平台编译 更改systemui 音量条(二)


    先上图
    在这里插入图片描述

    一.先写个demo,再将demo合并到systemUi中

    1.1自定义布局

    比较简单,1.画背景,2.画进度条背景,3.画进度(圆弧),4.画头部的小圆球,5.最后画中间的数字

    package com.zwt.myapplication3.view;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.graphics.SweepGradient;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    
    import androidx.core.content.ContextCompat;
    
    import com.zwt.myapplication3.R;
    
    
    public class VolumeRoundProgressBar extends View {
    
        private int bgColor;            //背景颜色
        private int outsideColor;       //外边框颜色
        private float outsideRadius;    //圆环半径
        private int insideColor;        //圆环进度条颜色
        private int progressTextColor;  //中心文字颜色
        private float progressTextSize; //中心文字大小
        private float progressWidth;    //进度条宽度
        private int progress;           //当前进度值
        private int maxProgress;        //最大进度的值
        private int direction;          //进度条方向,从哪个方向开始(右0下1左2上3)
    
        private Paint mPaint_bg;
        private Paint mPaint_out_progress;
        private Paint mPaint_progress;
        private Paint mPaint_ball;
        private Paint mPaint_text;
    
        private int[] mColorArray = new int[]{0xFFd42950, 0xFF3af3d4, 0xFF5adcf7, 0xFFd42950};
    
        int circlePoint;//圆心
        int radius; //计算半径
    
        public VolumeRoundProgressBar(Context context) {
            this(context, null);
        }
    
        public VolumeRoundProgressBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public VolumeRoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VolumeRoundProgressBar, defStyleAttr, 0);
    
            bgColor = typedArray.getColor(R.styleable.VolumeRoundProgressBar_background_color, 0xffffffff);
            outsideColor = typedArray.getColor(R.styleable.VolumeRoundProgressBar_outside_color, 0x36000000);
            outsideRadius = typedArray.getDimension(R.styleable.VolumeRoundProgressBar_outside_radius, 60.0f);
            insideColor = typedArray.getColor(R.styleable.VolumeRoundProgressBar_inside_color, 0xFF303F9F);
            progressTextColor = typedArray.getColor(R.styleable.VolumeRoundProgressBar_progress_text_color, 0xFF303F9F);
            progressWidth = typedArray.getDimension(R.styleable.VolumeRoundProgressBar_progress_width, 60.0f);
            progress = typedArray.getInt(R.styleable.VolumeRoundProgressBar_progress, 0);
            maxProgress = typedArray.getInt(R.styleable.VolumeRoundProgressBar_max_progress, 100);
            direction = typedArray.getInt(R.styleable.VolumeRoundProgressBar_direction, 1);
            typedArray.recycle();
    
            mPaint_bg = new Paint();
            mPaint_out_progress = new Paint();
            mPaint_progress = new Paint();
            mPaint_ball = new Paint();
            mPaint_text = new Paint();
    
            initPaint();
        }
    
        public VolumeRoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            circlePoint = getWidth() / 2;
            radius = (int) (circlePoint-progressWidth);
    
    
        }
    
        @SuppressLint("DrawAllocation")
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int circlePoint = getWidth() / 2;
            int radius = (int) (circlePoint-progressWidth); //计算半径
            //0.背景色圆
            canvas.drawCircle(circlePoint, circlePoint, (int) (circlePoint-progressWidth/2), mPaint_bg);// 画出圆
    
            //1.画背景(内层圆)
            canvas.drawCircle(circlePoint, circlePoint, radius, mPaint_out_progress);// 画出圆
    
            //2.画进度(圆弧)
            Matrix matrix = new Matrix();//用于定义的圆弧的形状和大小的界限
            matrix.postRotate(getDegree(direction), circlePoint, circlePoint);
            SweepGradient sweepGradient = new SweepGradient(circlePoint, circlePoint, mColorArray, null);
            sweepGradient.setLocalMatrix(matrix);               //设置背景图片开始位置
    //        mPaint1.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
            mPaint_progress.setShader(sweepGradient);           //设置背景颜色
            RectF oval = new RectF(circlePoint - radius, circlePoint - radius, circlePoint + radius, circlePoint + radius);
            canvas.drawArc(oval, getDegree(direction), (360 *progress / maxProgress),false, mPaint_progress);
    
            //3.头部小圆球
            float swipe = (360 *progress / maxProgress);
            float radians = (float) (((swipe - 90) / 2) / 180 * 2 * Math.PI);
            float endX = circlePoint + radius * (float) Math.cos(radians);//x坐标
            float endY = circlePoint + radius * (float) Math.sin(radians);//y坐标
    
            canvas.drawCircle(endX, endY, 12, mPaint_ball);
    
    
    
           //4.中间文字
            Rect rect = new Rect();
            mPaint_text.setTextSize((float) (radius*0.8));
            String progressText = (int)(((float)progress / maxProgress) * 100) + "";
            Log.d("zwt",maxProgress+":::::progress::"+progress+"progressText::"+progressText);
            mPaint_text.getTextBounds(progressText, 0, progressText.length(), rect);
            Paint.FontMetricsInt fontMetrics = mPaint_text.getFontMetricsInt();
            int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top)/2 - fontMetrics.top;//获得文字的基准线
            canvas.drawText(progressText, (getMeasuredWidth()-rect.width()) / 2, baseline, mPaint_text);
        }
    
    
        private void initPaint(){
            int circlePoint = getWidth() / 2;
            int radius = (int) (circlePoint-progressWidth); //计算半径
            /************************* 圆环背景 ****************************/
            mPaint_bg.setColor(bgColor);                //背景颜色
            mPaint_bg.setStyle(Paint.Style.FILL);       //实心
            //mPaint_bg.setStrokeWidth(progressWidth);  //设置圆的宽度
            mPaint_bg.setStrokeCap(Paint.Cap.ROUND);    //设置圆角
            mPaint_bg.setAntiAlias(true);               //消除锯齿
    
            /************************* 外环背景 ****************************/
            mPaint_out_progress.setColor(outsideColor);           //背景颜色
            mPaint_out_progress.setStyle(Paint.Style.STROKE);     //空心
            mPaint_out_progress.setStrokeWidth(progressWidth);    //设置圆的宽度
            mPaint_out_progress.setStrokeCap(Paint.Cap.ROUND);    //设置圆角
            mPaint_out_progress.setAntiAlias(true);               //消除锯齿
    
            /************************* 进度圆环 ****************************/
            mPaint_progress.setStyle(Paint.Style.STROKE);       //空心
            //mPaint_out_progress.setColor(insideColor);          //设置进度条的颜色,纯色,这里使用了SweepGradient渐变色
            mPaint_progress.setStrokeWidth(progressWidth);      //设置圆环宽度
            mPaint_progress.setStrokeCap(Paint.Cap.ROUND);      //设置圆角
            mPaint_progress.setAntiAlias(true);                 //消除锯齿
    
            /************************* 头部小圆球 ****************************/
            mPaint_ball.setStyle(Paint.Style.FILL);     // 填充
            mPaint_ball.setStrokeCap(Paint.Cap.ROUND);  // 设置圆角
            mPaint_ball.setAntiAlias(true);             // 设置抗锯齿
            mPaint_ball.setDither(true);                // 设置抖动
            mPaint_ball.setStrokeWidth((float) (progressWidth*0.9));
            mPaint_ball.setColor(Color.WHITE);
            /************************* 音量数字 ****************************/
            mPaint_text.setColor(progressTextColor);
            mPaint_text.setStyle(Paint.Style.FILL);
            mPaint_text.setAntiAlias(true);
        }
    
    
        private float getDegree(int direction){
            return 90*direction;
        }
    
        //设置进度
        public void setProces(int proces){
            if (proces < 0 ){
                return;
            }else if (proces >= maxProgress){
                this.progress = maxProgress;
            }else {
                this.progress = proces;
            }
            postInvalidate();
        }
    
        public int getProces(){
            return this.progress;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192

    SweepGradient 设置渐变色背景,Matrix 可设置渐变色起始位置以及每种颜色在进度条中的占比
    attrs.xml

    
    <resources>
        <declare-styleable name="VolumeRoundProgressBar">
            <attr name="background_color" format="color" />
            <attr name="outside_color" format="color" />
            <attr name="outside_radius" format="dimension" />
            <attr name="inside_color" format="color" />
            <attr name="progress_text_color" format="color" />
            <attr name="progress_width" format="dimension" />
            <attr name="max_progress" format="integer" />
            <attr name="progress" format="integer" />
            <attr name="direction">
                <enum name="right" value="0" />
                <enum name="bottom" value="1" />
                <enum name="left" value="2" />
                <enum name="top" value="3" />
            attr>
        declare-styleable>
    resources>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.2调用

    布局activity_main.xml

    "1.0" encoding="utf-8"?>
    "http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:background="#AA58c693"
        android:orientation="vertical">
    
    
        <!--    .zwt.myapplication3.view.FlyMusicView-->
        <!--        android:id="@+id/FlyMusicView"-->
        <!--        android:layout_width="match_parent"-->
        <!--        android:layout_height="match_parent"-->
        <!--        tools:ignore="InvalidId" />-->
        .zwt.myapplication3.view.VolumeRoundProgressBar
            android:id="@+id/VolumeRoundProgressBar"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:progress="56"
            app:direction="top"
            android:background="#aac5d687"/>
    
        

    调用

    public class MainActivity extends AppCompatActivity {
    
        private VolumeRoundProgressBar volumeRoundProgressBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d("zwt", "onClick: "+(volumeRoundProgressBar.getProces()+1));
                    volumeRoundProgressBar.setProces(volumeRoundProgressBar.getProces()+1);
                }
            });
    
    
            findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    volumeRoundProgressBar.setProces(volumeRoundProgressBar.getProces()-1);
                }
            });
            
            volumeRoundProgressBar = findViewById(R.id.VolumeRoundProgressBar);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    二.合并到systemui中

    首先先将上面demo中的自定义类放入到下面的位置

    frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeRoundProgressBar.java

    更改布局

    Z:\git_repository\frameworks\base\packages\SystemUI\res\layout\volume_dialog_row.xml

    
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:tag="row"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:theme="@style/qs_theme">
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@android:color/transparent"
            android:gravity="center"
            android:layout_gravity="center"
            android:orientation="horizontal" 
    	    android:visibility="gone">
            <com.android.keyguard.AlphaOptimizedImageButton
                android:id="@+id/volume_row_icon"
                style="@style/VolumeButtons"
                android:layout_width="@dimen/volume_dialog_tap_target_size"
                android:layout_height="@dimen/volume_dialog_tap_target_size"
                android:background="@drawable/ripple_drawable_20dp"
                android:tint="@color/accent_tint_color_selector"
                android:soundEffectsEnabled="false" />
            <TextView
                android:id="@+id/volume_row_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLength="10"
                android:maxLines="1"
                android:visibility="gone"
                android:textColor="?android:attr/colorControlNormal"
                android:textAppearance="@style/TextAppearance.Volume.Header" />
            <TextView
                android:id="@+id/volume_value"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="26dip" />
            <FrameLayout
                android:id="@+id/volume_row_slider_frame"
                android:layout_height="match_parent"
                android:layoutDirection="ltr"
                android:layout_width="@dimen/volume_dialog_row_width">
                <SeekBar
                    android:id="@+id/volume_row_slider"
                    android:clickable="false"
                    android:layout_width="@dimen/volume_dialog_row_width"
                    android:layout_height="match_parent"
                    android:layoutDirection="ltr"
                    android:layout_gravity="center"
                    android:rotation="0" />
            FrameLayout>
        LinearLayout>
        <com.android.systemui.volume.VolumeRoundProgressBar
                    android:id="@+id/volume_round_progressBar"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    app:progress="0"
                    app:direction="top"
                    />
    
        <include layout="@layout/volume_dnd_icon"/>
    
    FrameLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    在这里插入图片描述
    先将原来的音量条隐藏掉,再将自定义的布局加入上去

    音量处理流程可以看这位大神
    https://blog.csdn.net/qq_33668392/article/details/118679631
    具体就是当phonewindowsmanager 监听到音量键按下的时候,会有一个server通知底层改变音量,同时 通知systemui改变ui

    更改音量逻辑
    \frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeDialogImpl.java

    diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImp
    index 7d337f3..bc16788 100755
    --- a/frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
    +++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
    @@ -95,6 +95,7 @@ import com.android.systemui.plugins.VolumeDialogController.StreamState;
     import com.android.systemui.statusbar.phone.StatusBar;
     import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
     import com.android.systemui.statusbar.policy.DeviceProvisionedController;
    +import com.android.systemui.volume.VolumeRoundProgressBar;
     
     import java.io.PrintWriter;
     import java.util.ArrayList;
    @@ -185,6 +186,7 @@ public class VolumeDialogImpl implements VolumeDialog {
             mWindow = mDialog.getWindow();
             mWindow.requestFeature(Window.FEATURE_NO_TITLE);
             mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    +               //mWindow.setBackgroundDrawable(new ColorDrawable(Color.BLUE));
             mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
             mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    @@ -194,26 +196,29 @@ public class VolumeDialogImpl implements VolumeDialog {
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
             mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
             mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
             final WindowManager.LayoutParams lp = mWindow.getAttributes();
             lp.format = PixelFormat.TRANSLUCENT;
             lp.setTitle(VolumeDialogImpl.class.getSimpleName());
    
             if (mContext.getResources().getBoolean(R.bool.config_tvVolumeBar)) {
                 lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
    +            lp.y = 400;
    +            lp.alpha=1.0f;
             }
             else 
                 lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
     
             lp.windowAnimations = -1;
             mWindow.setAttributes(lp);
             mDialog.setCanceledOnTouchOutside(true);
             mDialog.setContentView(R.layout.volume_dialog);
    +        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
             mDialog.setOnShowListener(dialog -> {
                 if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2);
                 mDialogView.setAlpha(0);
                 mDialogView.animate()
                         .alpha(1)
                         .translationX(0)
    @@ -396,6 +401,7 @@ public class VolumeDialogImpl implements VolumeDialog {
             row.volumeValue = (TextView) row.view.findViewById(R.id.volume_value);
    
    +        row.volumeRoundProgressBar = (VolumeRoundProgressBar) row.view.findViewById(R.id.volume_round_progressBar);
     
             row.icon = row.view.findViewById(R.id.volume_row_icon);
             row.icon.setImageResource(iconRes);
    @@ -979,6 +985,7 @@ public class VolumeDialogImpl implements VolumeDialog {
             row.volumeValue.setText(String.valueOf(vlevel));
             
    +        row.volumeRoundProgressBar.setProces(vlevel);
         }
     
         private void recheckH(VolumeRow row) {
    @@ -1210,6 +1217,7 @@ public class VolumeDialogImpl implements VolumeDialog {
                     if (mRow.requestedLevel != userLevel) {
                         mRow.volumeValue.setText(String.valueOf(userLevel));
    +                    mRow.volumeRoundProgressBar.setProces(userLevel);
                         mController.setStreamVolume(mRow.stream, userLevel);
                         mRow.requestedLevel = userLevel;
    @@ -1322,5 +1330,6 @@ public class VolumeDialogImpl implements VolumeDialog {
    		 private int lastAudibleLevel = 1;
             private FrameLayout dndIcon;
             private TextView volumeValue;
    +        private VolumeRoundProgressBar volumeRoundProgressBar;
         }
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    最后实现效果
    在这里插入图片描述
    Demo地址:https://download.csdn.net/download/weixin_44128558/86338338

    百度云:https://pan.baidu.com/s/19ndMC4-IXEgGkow4nyDtog
    提取码:fw4u

  • 相关阅读:
    【算法|双指针|链表】反转链表
    C/C++编译问题,摆脱编译时的动态库依赖
    java游戏制作-拼图游戏
    软件测试01
    ES6 从入门到精通 # 12:数组的扩展方法一
    SpringIOC容器Bean对象的实例化模拟
    23. 从零用Rust编写正反向代理,流控小姐姐的温柔一刀!
    .NET App 与Windows系统媒体控制(SMTC)交互
    基于springboot的作业管理系统设计与实现
    Bootstrap Blazor Table 组件(四)自定义列生成
  • 原文地址:https://blog.csdn.net/weixin_44128558/article/details/125790286