ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

自定义View之圆形进度条的实现,带有心跳动画效果!

2021-08-04 15:57:38  阅读:173  来源: 互联网

标签:自定义 进度条 int void float private progress public View


今天我们一起来实现一个带有缺口的自定义view进度条,带有心跳动画效果

看一下截图是什么效果
效果

说到自定义view我们就需要实现onDraw() 方法, 去操作其携带的Canvas参数,通过drawXXX()系列方法来绘制出自己想要的布局样式。

怎样实现一个缺口向下同时带有心跳动画的进度条呢?

思路

1. 通过drawArc()方法绘制两个空心的扇型圆

第一个扇型是未加载的样式,第二个扇型是进度条样式

 RectF rect = new RectF(left, top, right, bottom);
        canvas.drawArc(rect, startPosition, endPosition, false, paint);
        canvas.save(); // 保存一下。
        //
        paint.setColor(Color.parseColor(progressColor));
        //paint.setDither(true);
        if(!TextUtils.isEmpty(shadowColor))
        paint.setShadowLayer(shadowSize,1,1,Color.parseColor(shadowColor));
        canvas.drawArc(rect, startPosition, progress, false, paint);
        canvas.save(); // 保存一下。

需要注意的是startPosition & endPosition 这两个参数是通过计算得来, 首先要了解canvas.drawArc这几个参数的意思:

第一个参数rect是确定位置,RectF的几个位置信息参数分别代表:

left= 最左边view视图边界到绘制画布最左边的距离;
top=最顶部view视图的边界到绘制画布最上边的距离;
right=最左边view视图的边界到绘制画布最右边的距离;
bottom=最顶部view视图的边界到绘制画布最底部的距离

第二个参数开始画扇形的角度, 这个角度是以3点钟方向为0角度,顺时针旋转360度再回到3点钟的方向。

第三个参数是结束扇形的角度。

第四个参数是否要画一条线与中心点相连,这个还是好理解的。

第五个参数就是画笔paint,专门用来设定一些画笔属性。

现在来计算缺口的位置,计算方式也很简单,假设我们的缺口大小是30度,并且缺口的位置是垂直向下的,我们需要先确定垂直向下的角度为90度,也就是6点钟方向(3点为起始位置,到6点方向为90度),这条线将我们需要展示缺口一分为二,左右两边各占15度角,那么开始扇形的位置的计算方式就是90.0f + (30/2)。 确定了开始画扇形的位置,就可以计算出结束扇形的角度位置了,缺口大小为30度,从105度的地方顺时针画360度就是一个完整的圆了, 当然我们不需要一个完整的圆, 那么我们用360度减去缺口大小,就是缺口结束的位置。

通过计算, 就可以提供下列方法,抛出设置缺口大小的方法。

   /**
     *  计算缺口位置
     * @param gap
     */
    private void setGapPosition(float gap){
        startPosition = 90.0f + (gap/2);
        endPosition = 360 - gap;
    }

思路:通过改变圆的半径实现心跳动画

看onDraw()方法中,先确定圆的半径,这里(l+levelOffset)代表在动态计算圆的半径,要实现心跳动画,就必须要动态改变圆的半径。

 float r = getMeasuredWidth() / (l+levelOffset)-5; //

(l+levelOffset)中的 “l” 是 圆的等级大小,最低等级是2,2是最大的圆,与布局一样大,等级越大,画的圆就越小:

    // 圆的大小,默认是最小规格的
    private int level = XXXXXX;
    // XX = 控件 / 2 = 圆的半径
    public static final int XX = 2;
    // XXX = 控件 / 3 = 圆的半径
    public static final int XXX = 3;
    // XXXX = 控件 / 4 = 圆的半径
    public static final int XXXX = 4;
    // XXXXX = 控件 / 5 = 圆的半径
    public static final int XXXXX = 5;
    // XXXXXX = 控件 / 6 = 圆的半径
    public static final int XXXXXX = 6;
    // 修改画笔的宽度,进度条的粗细设置

levelOffset的计算方式:

   /**
     *  计算偏移量/ 动态控制圆的大小
     */
    public void reconOffset(){
        if(isStarAnimation){
            if(levelOffset <= 0f || isAdd){
                // 增加
                isAdd = true;
                levelOffset +=0.02f;
                if(levelOffset>=0.3)isAdd=false;
            }else if(levelOffset>=0f && !isAdd){
                //减小
                isAdd = false;
                levelOffset -=0.02f;
            }
        }else{
            levelOffset = 0;
        }
    }

以上就介绍了实现的思路与计算方式,关于reconOffset()方法,可以自己尝试修改一下数值, 跑一下,看是什么效果。

完整代码如下:

package com.gongjiebin.drawtest;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import java.text.DecimalFormat;

/**
 * @author gongjiebin
 */
public class JJumpProgress extends View {

    public JJumpProgress(Context context) {
        super(context);
        initView();
    }

    public JJumpProgress(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public JJumpProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


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

    }


    public void initView(){
        setGapPosition(this.gap);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        /**
         *  得到view的宽度模式
         *  取值-  MeasureSpec.UNSPECIFIED view的大小没有限制,可以是任意大小
         *  取值-  MeasureSpec.EXACTLY 当前的尺寸大小就是view的大小 相当于match_parent 如果是具体的值也是这个
         *  取值-  MeasureSpec.AT_MOST View能取的尺寸大小不能超过当前值大小 相当于wrap_content
         */
//        int widthSize = getSize(100, widthMeasureSpec);
        int heightSize = getSize(200, heightMeasureSpec);

        int widthSize = getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        int heightSize = getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);
//        int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
//        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        // Log.i("GJB", "widthSize=" + widthSize + "  heightSize=" + heightSize);

        // 填充大小
        setMeasuredDimension(widthSize, heightSize);

    }


    /**
     * 通过默认值和widthMeasureSpec/heightMeasureSpec获取控件的最终宽度
     *
     * @param defSize 默认值
     */
    public int getSize(int defSize, int measureSpec) {
        /**
         *  得到控件大小。 确定模式
         */
        int widthModel = MeasureSpec.getMode(measureSpec);

        int size = defSize;
        switch (widthModel) {
            case MeasureSpec.UNSPECIFIED: //撑满布局。
                // 没有指定大小。则使用默认大小
                size = defSize;
                break;
            case MeasureSpec.EXACTLY:
                size = MeasureSpec.getSize(measureSpec);
                break;
            case MeasureSpec.AT_MOST:// 内容包裹
                // 指定大小了,返回指定的大小-固定值了也取当前view 的大小
                size = MeasureSpec.getSize(measureSpec);

        }

        return size;
    }


    /**
     * 进度条
     */
    private float progress = 0f;
    // 缺口结束位置
    private float endPosition;
    // 缺口开始位置
    private float startPosition;
    // 进度文字
    private String progressTxt = "";
    // 偏移量
    private float offset = 5f;
    // 缺口 。设置圆缺口的大小,默认30度
    private float gap = 30;
    // 进度条的颜色 #000000 - 十六进制表达
    private String progressColor;
    // 进度条的颜色 #000000 - 背景圆的颜色
    private String bg_color;
    // 阴影的颜色
    private String shadowColor;
    // 阴影的大小
    private float shadowSize = 5;
    // 字体颜色 -- 默认黑色的。
    private String textColor = "#000000";
    // 默认显示百分比 / false 不显示
    private boolean isShowPercentage;
    // 字体大小
    private float textSize;

    // 圆的大小,默认是最小规格的
    private int level = XXXXXX;
    // 等级动画偏移量
    private float levelOffset=0;
    // XX = 控件 / 2 = 圆的半径
    public static final int XX = 2;
    // XXX = 控件 / 3 = 圆的半径
    public static final int XXX = 3;
    // XXXX = 控件 / 4 = 圆的半径
    public static final int XXXX = 4;
    // XXXXX = 控件 / 5 = 圆的半径
    public static final int XXXXX = 5;
    // XXXXXX = 控件 / 6 = 圆的半径
    public static final int XXXXXX = 6;
    // 修改画笔的宽度,进度条的粗细设置
    private float strokeWidth=10;

    public void setStrokeWidth(float strokeWidth) {
        this.strokeWidth = strokeWidth;
    }

    private boolean isStarAnimation;

    public boolean isStarAnimation() {
        return isStarAnimation;
    }

    public void setStarAnimation(boolean starAnimation) {
        isStarAnimation = starAnimation;
    }

    public void setLevel(int level) {
        this.level = level;
    }


    public void setProgressTxt(String progressTxt) {
        this.progressTxt = progressTxt;
    }

    public int getLevel() {
        return level;
    }

    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }

    public void setShowPercentage(boolean percentage) {
        this.isShowPercentage = percentage;
    }



    public void setTextColor(String textColor) {
        this.textColor = textColor;
    }

    public void setShadowSize(float shadowSize) {
        this.shadowSize = shadowSize;
    }

    public void setShadowColor(String shadowColor) {
        this.shadowColor = shadowColor;
    }

    public void setBg_color(String bg_color) {
        this.bg_color = bg_color;
    }

    public void setProgressColor(String progressColor) {
        // 关闭硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        this.progressColor = progressColor;
    }

    public void setGap(float gap) {
        this.gap = gap;
        setGapPosition(this.gap);
    }


    /**
     *  切换圆的大小
     * @param level
     */
    public void changeLevel(int level){
        this.setLevel(level);
        // 切换的时候不要动画
        this.setStarAnimation(false);

        // 刷新Ui
        invalidate();
    }


    /**
     *  计算缺口位置
     * @param gap
     */
    private void setGapPosition(float gap){
        startPosition = 90.0f + (gap/2);
        endPosition = 360 - gap;
    }

    /**
     *  设置每次的偏移量。。越小动画执行的越慢, 越大动画执行越快
     * @param offset
     */
    public void setOffset(float offset) {
        this.offset = offset;
    }


    /**
     * 设置进度
     *
     * @param progress 取值 : 0-100
     */
    public void setProgress(final float progress) {
        // 计算当前的值
        this.progress = endPosition / 100 * progress;
        //刷新view
        invalidate();
    }


    /**
     * 有动画效果的执行
     *
     * @param progress 需要到达的进度条位置
     */
    public void animationSetProgress(float progress) {
        // 换算成view能够认识的数值
        float jd = progress * (endPosition / 100);
        if(jd == 0){
            setProgress(jd);
        }else{
            animationStart(jd, this.offset,progress);
        }
    }


    /**
     * @param progress 需要到达的进度条位置
     */
    public void animationSetProgress(float progress,boolean isStarAnimation) {
        this.setStarAnimation(isStarAnimation);
        this.animationSetProgress(progress);
    }


    /**
     *  更改文字
     * @param offset
     */
    public void setTextCenter(float progress,float offset,float thasProgress){
        if(!isShowPercentage)return;
        //Log.i("TAG",isShowPercentage+"");
        float b =  (offset / progress * thasProgress);
        DecimalFormat df = new DecimalFormat("#.00");
        String t = df.format(b);
        progressTxt = t+"%";
    }

    /**
     * @param progress 总进度
     * @param offset   偏移量 每次偏移的角度
     */
    private void animationStart(final float progress, float offset,float thasProgress) {
        // 得到百分比
        float tPro =  (offset / progress * thasProgress);
        if(offset == progress){
            this.progress = offset;
            setTextCenter(progress,offset,thasProgress);
            invalidate();
            isStarAnimation = false;
            if(onChangeListener!=null)onChangeListener.onProgress(tPro);
            return;
        }

        // 换算百分比。
        if(offset >= progress){
            // 修改参数
            offset = progress;
            this.progress = offset;
            setTextCenter(progress,offset,thasProgress);
        }else{
            this.progress = offset;
            setTextCenter(progress,offset,thasProgress);
           //("GJB","offset" + offset +"progress =" +progress);
            offset+=this.offset;
        }
        //
        if(onChangeListener!=null)onChangeListener.onProgress(tPro);
        invalidate();
        Message message = new Message();
        float[] sets = new float[]{progress,offset,thasProgress};
        message.obj = sets;
        handler.sendMessage(message);
    }

   Handler handler = new Handler(new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
           float set[] = (float[]) msg.obj;
           animationStart(set[0],set[1],set[2]);
           return false;
       }
   });



    public boolean isAdd = true;

    /**
     *  计算偏移量/ 控制圆的大小
     */
    public void reconOffset(){
        if(isStarAnimation){
            if(levelOffset <= 0f || isAdd){
                // 增加
                isAdd = true;
                levelOffset +=0.02f;
                if(levelOffset>=0.3)isAdd=false;
            }else if(levelOffset>=0f && !isAdd){
                //减小
                isAdd = false;
                levelOffset -=0.02f;
            }
        }else{
        //不需要动画
            levelOffset = 0;
        }
    }



    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float l = Float.valueOf(level);
        // 计算半径的偏移大小
        this.reconOffset();
        // 计算圆的半径
        float r = getMeasuredWidth() / (l+levelOffset)-5; //
      //  Log.i("GJB","r = "+r + " levelOffset" + levelOffset);
        // x坐标 中间位置
        int c_x = getLeft() + (getMeasuredWidth() / 2);
        // y坐标 中间位置
        int c_y = getTop() + (getMeasuredHeight() / 2);

        // 创建画笔
        Paint paint = new Paint();
        // 画笔的颜色 -
        paint.setColor(Color.parseColor(bg_color));
        // **当绘图样式为的时候,setStrokeJoin这个方法用于指定线条连接拐角样式: 相当于圆角
        //paint.setStrokeJoin(Paint.Join.ROUND);
        // 画笔的形状 Paint.Cap.Round 圆 ,Cap.SQUARE 方
        paint.setStrokeCap(Paint.Cap.ROUND);
        //画笔样式。 Paint.Style.STROKE为一条线。Paint.Style.FILL是从起点开始。一直到终点为止,形成一扇形的绘制区。Paint.Style.FILL_AND_STROKE 为扇形区再加上一个圈
        paint.setStyle(Paint.Style.STROKE); // 空心
        paint.setStrokeWidth(strokeWidth);
        paint.setAntiAlias(true); // 设置锯齿效果 取值true 代表

        // 画一个红色的圆在空心的中间位置
        float left = c_x - r;
        float top = c_y - r;
        float right = c_x + r;
        float bottom = c_y + r;
        // RectF - left计算的是从左边边界到扇形最左边的位置,
        // RectF -right是计算的是从左边边界到扇形最右边的位置
        // RectF -top 是计算的是从顶部边界到扇形最上边的位置
        // RectF -bottom 是计算的是从顶部边界到扇形最下边的位置
        RectF rect = new RectF(left, top, right, bottom);
        canvas.drawArc(rect, startPosition, endPosition, false, paint);
        canvas.save(); // 保存一下。
        //
        paint.setColor(Color.parseColor(progressColor));
        //paint.setDither(true);
        if(!TextUtils.isEmpty(shadowColor))
        paint.setShadowLayer(shadowSize,1,1,Color.parseColor(shadowColor));
        canvas.drawArc(rect, startPosition, progress, false, paint);
        canvas.save(); // 保存一下。


        if(!TextUtils.isEmpty(progressTxt)){
            // 在圆心画一个文字。
            Paint textPaint = new Paint();
            // 画笔的颜色

            textPaint.setColor(Color.parseColor(textColor));
            textPaint.setAntiAlias(true); // 设置锯齿效果 取值true 代表
            // 计算textView的字体大小随着布局的变化而变化
            float thasSize = 0;
            if(textSize == 0){
                thasSize = r / 6;
            }else{
                thasSize = textSize;
            }
           // Log.i("TAG",progressTxt+" progressTxt");
            textPaint.setTextSize(sp2px(thasSize));

            // 字体加粗
            textPaint.setFakeBoldText(true);
            // 测量一下文字的宽度
            float textSize = textPaint.measureText(progressTxt); // 测量文字的大小
            float center = c_x - (textSize/2);
            /**
             * 其中 y 表示文字的基线(baseline )所在的坐标,说白了就是我们小学写字用的那种带有横线的本子(一般都是按照一条基线来写字是吧?),
             * 用于规范你写的字是否成一条直线,否则很多人写着写着就往上飘了。而 x 坐标就是文字绘制的起始水平坐标,但是每个文字本身两侧都有一定的间隙,
             * 故实际文字的位置会比 x 的位置再偏右侧一些。
             */
            canvas.drawText(progressTxt,center,c_y,textPaint);
            canvas.save();
        }
    }


    private int sp2px(float spValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, getResources().getDisplayMetrics());
    }


    private OnChangeListener onChangeListener;

    public void setOnChangeListener(OnChangeListener onChangeListener) {
        this.onChangeListener = onChangeListener;
    }

    public interface OnChangeListener{
        /**
         *  当前进度回调
         * @param progress
         */
        void onProgress(float progress);
    }
}

MainActivity完整代码如下(使用方法)

package com.gongjiebin.drawtest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private JJumpProgress jumpProgress;

    private Button btn_pull;

    private Button btn_level;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ViewGroup rootView = (ViewGroup) LayoutInflater.from(getBaseContext()).inflate(R.layout.activity_main, null);
        setContentView(rootView);

        btn_pull = rootView.findViewById(R.id.btn_pull);
        btn_level = rootView.findViewById(R.id.btn_level);


        jumpProgress = rootView.findViewById(R.id.dv_jd);
        jumpProgress.setGap(30f);// 设置缺口的大小。
        jumpProgress.setOffset(5f); // 数值越大,动画效果越快
        jumpProgress.setBg_color("#E9E9E9"); 
        jumpProgress.setProgressColor("#FFDF2C32");
        jumpProgress.setShadowColor("#FFDF2C32");
        jumpProgress.setShadowSize(8);
        jumpProgress.setShowPercentage(true);
//        dv_jd.setTextSize(8);
        jumpProgress.setTextColor("#FFDF2C32");
//        dv_jd.setStrokeWidth(20);
        btn_pull.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                jumpProgress.animationSetProgress(100f, true);
            }
        });

        btn_level.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int level = jumpProgress.getLevel();
                if (level == JJumpProgress.XX) {
                    level = JJumpProgress.XXX;
                } else if (jumpProgress.getLevel() == JJumpProgress.XXX) {
                    level = JJumpProgress.XXXX;
                } else if (jumpProgress.getLevel() == JJumpProgress.XXXX) {
                    level = JJumpProgress.XXXXX;
                } else if (jumpProgress.getLevel() == JJumpProgress.XXXXX) {
                    level = JJumpProgress.XXXXXX;
                } else if (jumpProgress.getLevel() == JJumpProgress.XXXXXX) {
                    level = 10;
                } else if (jumpProgress.getLevel() == 10) {
                    level = 15;
                } else if (jumpProgress.getLevel() == 15) {
                    level = JJumpProgress.XX;
                }

                // 切换进度条圆的大小
                jumpProgress.changeLevel(level);
            }
        });

        initListener();
    }





    public void initListener() {
        jumpProgress.setOnChangeListener(new JJumpProgress.OnChangeListener() {
            @Override
            public void onProgress(float progress) {
                // 在这里可以显示你想显示的文本, 如果你已经开启了默认打开百分比请先关闭。setShowPercentage(false)
//                float price = progress / 100 * countPrice;
//                Log.i("TAG", "text=" + price + "progress =" + progress);
//                DecimalFormat df = new DecimalFormat("#.0");
//                String t = df.format(price);
//                dv_jd.setProgressTxt("¥" + t);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 完成百分之90。
        jumpProgress.animationSetProgress(90f, true);
    }


    @Override
    protected void onPause() {
        super.onPause();
    }
}


XML中使用:

  <com.gongjiebin.drawtest.JJumpProgress
        android:id="@+id/dv_jd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
/>

需要注意的是, 在使用时,可以看看代码中的注释,还是写的比较清楚的。 比如一些参数的设置,找到对应的set方法就可以啦。

 //进度
    private float progress = 0f;
    // 缺口结束位置
    private float endPosition;
    // 缺口开始位置
    private float startPosition;
    // 进度文字
    private String progressTxt = "";
    // 偏移量
    private float offset = 5f;
    // 缺口 。设置圆缺口的大小,默认30度
    private float gap = 30;
    // 进度条的颜色 #000000 - 十六进制表达
    private String progressColor;
    // 背景圆的颜色 #000000 - 十六进制表达
    private String bg_color;
    // 阴影的颜色  #000000 - 十六进制表达
    private String shadowColor;
    // 阴影的大小
    private float shadowSize = 5;
    // 字体颜色 -- 默认黑色的。
    private String textColor = "#000000";
    // 默认显示百分比 / false 不显示
    private boolean isShowPercentage;
    // 字体大小
    private float textSize;
    // 圆的大小,默认是最小规格的
    private int level = XXXXXX;
    // 修改画笔的宽度,进度条的粗细设置
    private float strokeWidth=10;

中间的文字默认按照百分比显示, 如果想显示其它文字,需要按照下列方式进行设置。

 jumpProgress.setShowPercentage(false);

动态改变文字的监听方法

jumpProgress.setOnChangeListener(new JJumpProgress.OnChangeListener() {
            @Override
            public void onProgress(float progress) {
                // 在这里可以显示你想显示的文本, 如果你已经开启了默认打开百分比请先关闭。setShowPercentage(false)
                float price = progress / 100 * countPrice;
                Log.i("TAG", "text=" + price + "progress =" + progress);
                DecimalFormat df = new DecimalFormat("#.0");
                String t = df.format(price);
                jumpProgress.setProgressTxt("¥" + t);
            }
        });

说明

关于textSize的设置, 如果设置了这个参数,那字体的动画效果就会消失了。不设置会根据进度条的大小变化而变化。 这个view的动画效果适合已经知道百分比的情况下使用(类似查看今天的步数,展示统计数据类), 当需要实时更新数据的进度条并不适合这个动画,或者说效果不是很好,但我们可以调用setProgress完成更新,只是不会出现心跳动画了。

   /**
     * 设置进度
     *
     * @param progress 取值 : 0-100
     */
    public void setProgress(final float progress) {
        // 计算当前的值
        this.progress = endPosition / 100 * progress;
        //刷新view
        invalidate();
    }

标签:自定义,进度条,int,void,float,private,progress,public,View
来源: https://blog.csdn.net/u014478555/article/details/119381949

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有