android——自定义控件(不停变化的textview、开关switch、动画效果的打勾)

一、从开始数字到结束数字,不断变化

import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.animation.AccelerateDecelerateInterpolator;

import androidx.appcompat.widget.AppCompatTextView;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;

/**
 * FileName: NumberAnimTextView
 * Date: 2020/12/14
 * Description: TextView动画,从开始到结束,数字不断变化
 * History:
 * <author> <time> <version> <desc>
 */

public class NumberAnimTextView extends AppCompatTextView {

    private String mNumStart = "0";  //
    private String mNumEnd; //

    private long mDuration = 1000;          // 动画持续时间 ms,默认1s

    private String mPrefixString = "";      // 前缀
    private String mPostfixString = "";     // 后缀

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

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

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

    public void setNumberString(String number) {
        setNumberString("0", number);
    }

    public void setNumberString(String numberStart, String numberEnd) {
        mNumStart = numberStart;
        mNumEnd = numberEnd;
        start();
//        if (checkNumString(numberStart, numberEnd)) {
//            // 数字合法 开始数字动画
//            start();
//        } else {
//            // 数字不合法 直接调用 setText 设置最终值
//            setText(mPrefixString + numberEnd + mPostfixString);
//        }
    }

    public void setDuration(long mDuration) {
        this.mDuration = mDuration;
    }

    public void setPrefixString(String mPrefixString) {
        this.mPrefixString = mPrefixString;
    }

    public void setPostfixString(String mPostfixString) {
        this.mPostfixString = mPostfixString;
    }

    private boolean isInt; // 是否是整数

    /**
     * 校验数字的合法性
     *
     * @param numberStart  开始的数字
     * @param numberEnd    结束的数字
     * @return 合法性
     */
    private boolean checkNumString(String numberStart, String numberEnd) {
        try {
            new BigInteger(numberStart);
            new BigInteger(numberEnd);
            isInt = true;
        } catch (Exception e) {
            isInt = false;
            e.printStackTrace();
        }
        try {
            BigDecimal start = new BigDecimal(numberStart);
            BigDecimal end = new BigDecimal(numberEnd);
            return end.compareTo(start) >= 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private void start() {
        ValueAnimator animator = ValueAnimator.ofObject(new BigDecimalEvaluator(), new BigDecimal(mNumStart), new BigDecimal(mNumEnd));
        animator.setDuration(mDuration);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                BigDecimal value = (BigDecimal) valueAnimator.getAnimatedValue();
                setText(mPrefixString + format(value) + mPostfixString);
            }
        });
        animator.start();
    }

    /**
     * 格式化 BigDecimal ,小数部分时保留两位小数并四舍五入
     *
     * @param bd  BigDecimal
     * @return 格式化后的 String
     */
    private String format(BigDecimal bd) {
        String pattern;
        if (isInt) {
            pattern = "#,###";
        } else {
            pattern = "#,##0.00";
        }
        DecimalFormat df = new DecimalFormat(pattern);
        return df.format(bd);
    }

    class BigDecimalEvaluator implements TypeEvaluator {
        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            BigDecimal start = (BigDecimal) startValue;
            BigDecimal end = (BigDecimal) endValue;
            BigDecimal result = end.subtract(start);
            return result.multiply(new BigDecimal("" + fraction)).add(start);
        }
    }
}

设置开始数字和结束数字即可:setNumberString("12345", "1234567")

二、自定义开关switch

import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import com.fslihua.my_application_1.R;


/**
 * 自定义开关Switch
 */
public class CustomSwitch extends View implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener{
    private final String TAG = CustomSwitch.class.getSimpleName();

    //默认的宽高比例
    private static final float DEFAULT_WIDTH_HEIGHT_PERCENT = 0.45f;
    //动画最大的比例
    private static final float ANIMATION_MAX_FRACTION = 1;

    private int mWidth,mHeight;

    //画跑道型背景
    private Paint mBackgroundPain;
    //画背景上的字
    private Paint mDisaboleTextPaint;//开启
    private Paint mEnableTextPaint;//关闭
    //画白色圆点
    private Paint mSlidePaint;

    //是否正在动画
    private boolean isAnimation;

    private ValueAnimator mValueAnimator;

    private float mAnimationFraction;

    private String openText;
    private String closeText;
    private int mOpenColor = Color.GREEN;
    private int mCloseColor = Color.GRAY;
    private int mCurrentColor = Color.GRAY;

    //监听
    private OnCheckedChangeListener mCheckedChangeListener;


    private boolean isChecked;
    public CustomSwitch(Context context) {
        super(context);
        init();
    }

    public CustomSwitch(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitch);
        openText = typedArray.getString(R.styleable.CustomSwitch_openText);
        closeText = typedArray.getString(R.styleable.CustomSwitch_closeText);
        mOpenColor = typedArray.getColor(R.styleable.CustomSwitch_openColor, Color.GREEN);
        mCloseColor = typedArray.getColor(R.styleable.CustomSwitch_closeColor, Color.GRAY);
        mCurrentColor = mCloseColor;
//        mWidth = typedArray.getInteger(R.styleable.CustomSwitch_customWidth,1);
//        mHeight = typedArray.getInteger(R.styleable.CustomSwitch_customHeight,1);
        typedArray.recycle();
        init();
    }

    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitch);
        openText = typedArray.getString(R.styleable.CustomSwitch_openText);
        closeText = typedArray.getString(R.styleable.CustomSwitch_closeText);
        mOpenColor = typedArray.getColor(R.styleable.CustomSwitch_openColor, Color.GREEN);
        mCloseColor = typedArray.getColor(R.styleable.CustomSwitch_closeColor, Color.GRAY);
        mCurrentColor = mCloseColor;
//        mWidth = typedArray.getInteger(R.styleable.CustomSwitch_customWidth,1);
//        mHeight = typedArray.getInteger(R.styleable.CustomSwitch_customHeight,1);
        typedArray.recycle();
        init();
    }

    private void init(){
        Log.e(TAG,"init()被调用");
        mBackgroundPain = new Paint();
        mBackgroundPain.setAntiAlias(true);
        mBackgroundPain.setDither(true);
        mBackgroundPain.setColor(Color.GRAY);
//        开启的文字样式
        mDisaboleTextPaint = new Paint();
        mDisaboleTextPaint.setAntiAlias(true);
        mDisaboleTextPaint.setDither(true);
        mDisaboleTextPaint.setStyle(Paint.Style.STROKE);
        mDisaboleTextPaint.setColor(Color.WHITE);
        mDisaboleTextPaint.setTextAlign(Paint.Align.CENTER);
//        关闭的文字样式
        mEnableTextPaint = new Paint();
        mEnableTextPaint.setAntiAlias(true);
        mEnableTextPaint.setDither(true);
        mEnableTextPaint.setStyle(Paint.Style.STROKE);
        mEnableTextPaint.setColor(Color.parseColor("#7A88A0"));
        mEnableTextPaint.setTextAlign(Paint.Align.CENTER);

        mSlidePaint = new Paint();
        mSlidePaint.setColor(Color.WHITE);
        mSlidePaint.setAntiAlias(true);
        mSlidePaint.setDither(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width =  MeasureSpec.getSize(widthMeasureSpec);
        int height = (int) (width*DEFAULT_WIDTH_HEIGHT_PERCENT);
        setMeasuredDimension(width,height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

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

    private void drawSlide(Canvas canvas){
        float distance = mWidth - mHeight;
//        Log.e(TAG,"distance = " + distance);
//        Log.e(TAG,"mAnimationFraction = " + mAnimationFraction);
//        canvas.drawCircle(mHeight/2+distance*mAnimationFraction,mHeight/2,mHeight/3,mSlidePaint);
        canvas.drawCircle(mHeight/2+distance*mAnimationFraction,mHeight/2, mHeight/2.5f,mSlidePaint);
//        canvas.drawCircle(mHeight/2+distance*mAnimationFraction, (float) (mHeight/2.2), (float) (mHeight/2.2),mSlidePaint);
    }

    private void drawBackground(Canvas canvas){
        Path path = new Path();
        RectF rectF = new RectF(0,0,mHeight,mHeight);
        path.arcTo(rectF,90,180);
        rectF.left = mWidth-mHeight;
        rectF.right = mWidth;
        path.arcTo(rectF,270,180);
        path.close();
        mBackgroundPain.setColor(mCurrentColor);
        canvas.drawPath(path,mBackgroundPain);

//        mDisaboleTextPaint.setTextSize(mHeight/2);
        mDisaboleTextPaint.setTextSize(mHeight/2.2f);
//        mEnableTextPaint.setTextSize(mHeight/2);
        mEnableTextPaint.setTextSize(mHeight/2.2f);
        Paint.FontMetrics fontMetrics = mDisaboleTextPaint.getFontMetrics();
        float top = fontMetrics.top;
        float bottom = fontMetrics.bottom;
//        基线位置
        int baseLine = (int) (mHeight/2 + (bottom-top)*0.3);

        if (!TextUtils.isEmpty(openText)){
            //启用
            mDisaboleTextPaint.setAlpha((int) (255*mAnimationFraction));
            canvas.drawText(openText,mWidth*0.3f,baseLine,mDisaboleTextPaint);
        }

        if (!TextUtils.isEmpty(closeText)){
            //启用
            mEnableTextPaint.setAlpha((int) (255*(1-mAnimationFraction)));
            canvas.drawText(closeText,mWidth*0.7f,baseLine,mEnableTextPaint); //第二个值改变x轴的位置
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_CANCEL:
                break;
            case MotionEvent.ACTION_UP:
                if (isAnimation){
                    return true;
                }
                if (isChecked){
                    startCloseAnimation();
                    isChecked = false;
                    if (mCheckedChangeListener!=null){
                        mCheckedChangeListener.onCheckedChanged(false);
                    }
                }else {
                    startOpeAnimation();
                    isChecked = true;
                    if (mCheckedChangeListener!=null){
                        mCheckedChangeListener.onCheckedChanged(true);
                    }
                }
                return true;


        }
        return super.onTouchEvent(event);
    }

    private void startOpeAnimation(){
        mValueAnimator = ValueAnimator.ofFloat(0.0f, ANIMATION_MAX_FRACTION);
        mValueAnimator.setDuration(500);
        mValueAnimator.addUpdateListener(this);
        mValueAnimator.addListener(this);
        mValueAnimator.start();
        startColorAnimation();
    }
    private void startCloseAnimation(){
        mValueAnimator = ValueAnimator.ofFloat(ANIMATION_MAX_FRACTION, 0.0f);
        mValueAnimator.setDuration(500);
        mValueAnimator.addUpdateListener(this);
        mValueAnimator.addListener(this);
        mValueAnimator.start();
        startColorAnimation();
    }

    private void startColorAnimation(){
        int colorFrom = isChecked?mOpenColor:mCloseColor; //mIsOpen为true则表示要启动关闭的动画
        int colorTo = isChecked? mCloseColor:mOpenColor;
        ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
        colorAnimation.setDuration(500); // milliseconds
        colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                mCurrentColor = (int)animator.getAnimatedValue();
            }

        });
        colorAnimation.start();
    }



    //设置监听
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener){
        mCheckedChangeListener = listener;
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean checked) {
        isChecked = checked;
        if (isChecked){
            mCurrentColor = mOpenColor;
            mAnimationFraction = 1.0f;
        }else {
            mCurrentColor = mCloseColor;
            mAnimationFraction = 0.0f;
        }
        invalidate();
    }

    @Override
    public void onAnimationStart(Animator animator) {
        isAnimation = true;
    }

    @Override
    public void onAnimationEnd(Animator animator) {
        isAnimation = false;
    }

    @Override
    public void onAnimationCancel(Animator animator) {
        isAnimation = false;
    }

    @Override
    public void onAnimationRepeat(Animator animator) {
        isAnimation = true;
    }

    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mAnimationFraction = (float) valueAnimator.getAnimatedValue();
        invalidate();
    }
    public interface OnCheckedChangeListener{
        void onCheckedChanged(boolean isChecked);
    }
}

attrs.xml代码

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--    开关按钮CustomSwitch的样式定义  -->
    <declare-styleable name="CustomSwitch">
        <attr name="closeText" format="string" />
        <attr name="openText" format="string" />
        <attr name="closeColor" format="color" />
        <attr name="openColor" format="color" />
        <attr name="customWidth" format="integer" />
        <attr name="customHeight" format="integer" />
    </declare-styleable>
</resources>

activity的xml代码:

<com.fslihua.my_application_1.cumstom_ui.CustomSwitch
        android:id="@+id/customSwitch"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_width="50dp"
        android:layout_height="25dp"
        app:closeColor="#6A6A6A"
        app:closeText="关"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

三、包含动画效果的打勾

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PathMeasure
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.view.animation.DecelerateInterpolator
import com.fslihua.my_application_1.R

/**
 * 创建时间:2023/11/9
 * 类说明:包含动画效果的打勾
 */
class AnimatedCheckView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
    private val circlePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val checkPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    private var circlePath = Path()
    private var checkPath = Path()
    private var circleColor = 0
    private var checkColor = 0
    private var pathLength = 0f
    // 默认值
    private var circleStrokeWidth = 1f
    private var checkStrokeWidth = 1f

    private val animator = ValueAnimator().apply {
        interpolator = DecelerateInterpolator()
        addUpdateListener {
            invalidate()
        }
    }

    private var animateTime: Float = 2f // 2秒

    init {

        context.theme.obtainStyledAttributes(attrs, R.styleable.AnimatedCheckView, 0, 0).apply {
            try {
                circleColor = getColor(R.styleable.AnimatedCheckView_circleColor, Color.BLACK)
                checkColor = getColor(R.styleable.AnimatedCheckView_checkColor, Color.BLACK)
                circleStrokeWidth = getDimension(R.styleable.AnimatedCheckView_circleStrokeWidth, dp2px(context, circleStrokeWidth)
                    .toFloat())
                checkStrokeWidth = getDimension(R.styleable.AnimatedCheckView_checkStrokeWidth, dp2px(context, checkStrokeWidth)
                    .toFloat())
                animateTime = getFloat(R.styleable.AnimatedCheckView_animateTime, animateTime)

                Log.i("AnimatedCheckView", "circleStrokeWidth: $circleStrokeWidth, checkStrokeWidth: $checkStrokeWidth" )
            } finally {
                recycle()
            }
        }

        circlePaint.apply {
            style = Paint.Style.STROKE
            strokeWidth = circleStrokeWidth
            color = circleColor
        }

        checkPaint.apply {
            style = Paint.Style.STROKE
            strokeWidth = checkStrokeWidth
            color = checkColor
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        val centerX = w / 2f
        val centerY = h / 2f
        val radius = w.coerceAtMost(h) / 2f - circleStrokeWidth / 2

        initPaths(centerX, centerY, radius)

        animator.apply {
            setFloatValues(0f, pathLength)
            duration = (animateTime * 1000).toLong()
            start()
        }

        Log.i("AnimatedCheckView", "w: $w, h: $h, centerX: $centerX, centerY: $centerY, radius: $radius" )
    }

    private fun initPaths(centerX: Float, centerY: Float, radius: Float) {
        circlePath.addCircle(centerX, centerY, radius, Path.Direction.CW)

        checkPath.apply {
            moveTo(centerX - radius / 2 - radius / 15, centerY + radius / 15)
            lineTo(centerX - radius / 2, centerY)
            lineTo(centerX - radius / 8, centerY + radius / 3)
            lineTo(centerX + radius / 2, centerY - radius / 3)
        }

        val measure = PathMeasure(circlePath, false)
        val circleLength = measure.length
        measure.setPath(checkPath, false)
        val checkLength = measure.length

        pathLength = circleLength + checkLength
    }


    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val measure = PathMeasure(circlePath, false)
        val dst = Path()

        val animatedValue = animator.animatedValue as Float
        val circleLength = measure.length
        if (animatedValue < circleLength) {
            measure.getSegment(0f, animatedValue, dst, true)
            canvas.drawPath(dst, circlePaint)
        } else {
            measure.getSegment(0f, circleLength, dst, true)
            canvas.drawPath(dst, circlePaint)

            measure.nextContour()
            measure.setPath(checkPath, false)
            dst.rewind()
            measure.getSegment(0f, animatedValue - circleLength, dst, true)
            canvas.drawPath(dst, checkPaint)
        }
    }

    fun dp2px(context: Context, dpVal: Float): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dpVal, context.resources.displayMetrics
        ).toInt()
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="AnimatedCheckView">
        <attr name="circleColor" format="color" />
        <attr name="checkColor" format="color" />
        <attr name="circleStrokeWidth" format="dimension" />
        <attr name="checkStrokeWidth" format="dimension" />
        <attr name="animateTime" format="float" />
    </declare-styleable>
</resources>

activity中的代码:

<com.fslihua.my_application_1.cumstom_ui.AnimatedCheckView
        android:id="@+id/ac_success"
        android:layout_width="55dp"
        android:layout_height="55dp"
        android:layout_marginTop="64dp"
        app:animateTime="0.7"
        app:checkColor="#3ACFA5"
        app:checkStrokeWidth="2dp"
        app:circleColor="#3ACFA5"
        app:circleStrokeWidth="2dp"
        app:layout_constraintStart_toEndOf="@+id/customSwitch"
        app:layout_constraintTop_toTopOf="parent" />

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习实战94-基于图卷积神经网络GCN模型的搭建以及在金融领域的场景

大家好,我是微学AI,今天给大家介绍一下深度学习实战94-基于图卷积神经网络GCN模型的搭建以及在金融领域的场景。文章首先介绍了GCN模型的原理及模型结构,随后提供了数据样例,并详细展示了实战代码。通过本文,读者可以深入了解GCN模型在金融场景下的应用,同时掌握代码的具…

使用标注工具并跑通官方yolov8分割segment自己的数据集

1.下载标注工具用于打标签 使用标注工具&#xff0c;后面会用到智能标注 点击 创建AI多边形后命令行就自动下载对应的模型 单机要选中的图像就行&#xff0c;就可以智能选中&#xff0c;双击设置标签 依次标注所有图片 &#xff0c;最后保存成json格式的文件 2.使用labelme2y…

关于mac下的nvm设置淘宝镜像源

1. 进入配置文件修改镜像源 vim ~/.bash_profile增加下面内容 export NVM_NODEJS_ORG_MIRRORhttps://npmmirror.com/mirrors/node/2. 查看远程node镜像 nvm ls-remote3. 下载镜像 nvm install 14.17.64. 使用镜像 nvm use 14.17.6

总台戏曲探访类创新节目《风味梨园》开播 探寻一座城市的戏曲文化地图

戏曲艺术犹如一颗璀璨的明珠&#xff0c;承载着中华民族千年的历史文化底蕴&#xff0c;以其独有的艺术魅力&#xff0c;如悠扬的旋律、精湛的表演&#xff0c;深深吸引着无数观众。而每一座城市隐匿其后的美食文化&#xff0c;恰似一首动人的诗篇&#xff0c;代表着人们对美好…

2013年国赛高教杯数学建模A题车道被占用对城市道路通行能力的影响解题全过程文档及程序

2013年国赛高教杯数学建模 A题 车道被占用对城市道路通行能力的影响 车道被占用是指因交通事故、路边停车、占道施工等因素&#xff0c;导致车道或道路横断面通行能力在单位时间内降低的现象。由于城市道路具有交通流密度大、连续性强等特点&#xff0c;一条车道被占用&#x…

数学建模算法与应用 第11章 偏最小二乘回归及其方法

目录 11.1 偏最小二乘回归概述 11.2 Matlab 偏最小二乘回归命令 Matlab代码示例&#xff1a;偏最小二乘回归 11.3 案例分析&#xff1a;化学反应中的偏最小二乘回归 Matlab代码示例&#xff1a;光谱数据的PLS回归 习题 11 总结 偏最小二乘回归&#xff08;Partial Least …

MySQL 【日期】函数大全(三)

DATEOFYEAREXTRACTFROM_DAYSFROM_UNIXTIMEHOURLAST_DAYLOCALTIMELOCALTIMESTAMP 1、DATEOFYEAR DATEOFYEAR(expr) &#xff1a;返回一个从 1 到 366 代表给定日期是一年中的第几天的数字。 如果指定的表达式不是一个合法的日期或者日期时间&#xff0c;DAYOFYEAR() 函数将返回…

无功补偿设备在室内及室外安装的区别

无功补偿设备在室内和室外的安装存在多方面的区别&#xff0c;包括环境条件、设备选择、安装要求以及维护方式。下面详细介绍两者的区别及相应的注意事项。 一、环境条件的差异 1、室内安装 温度和湿度&#xff1a;相对受控&#xff0c;温度变化较小&#xff0c;湿度可调节&…

k8s的部署和安装

k8s的部署和安装 一、Kubernets简介及部署方法 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个阶段&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参…

STM32传感器模块编程实践(六) 1.8寸液晶屏TFT LCD彩屏简介及驱动源码

文章目录 一.概要二.TFT彩屏主要参数三.TFT彩屏参考原理图四.TFT彩屏模块接线说明五.模块SPI通讯协议介绍六.TFT彩屏模块显示1.显示英文字符串2.显示数字3.显示中文 七.TFT彩屏实现图片显示八.STM32单片机1.8寸 TFT LCD显示实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 九…

Redis set类型 zset类型

set类型 类型介绍 集合类型也是保存多个字符串类型的元素的&#xff0c;但和列表类型不同的是&#xff0c;集合中 1&#xff09;元素之间是⽆序 的 2&#xff09;元素不允许重复 ⼀个集合中最多可以存储 个元素。Redis 除了⽀持 集合内的增删查改操作&#xff0c;同时还⽀持多…

【Vue】扫盲(五)Vue 的生命周期与钩子函数详解

【Vue】Vue扫盲&#xff08;一&#xff09;事件标签、事件修饰符&#xff1a;click.prevent click.stop click.stop.prevent、按键修饰符、及常用指令 【Vue】Vue扫盲&#xff08;二&#xff09;指令&#xff1a;v-for 、v-if、v-else-if、v-else、v-show 【Vue】Vue扫盲&…

多种方式确定Linux是CentOS还是Ubuntu

目录 前言正文 前言 对应的基本知识比较少&#xff0c;以下只是记录总结 由于目前使用的是centos&#xff0c;后续找到linux会对应补充 正文 要确定Linux系统是CentOS还是Ubuntu&#xff0c;可以通过以下几种方式进行分析 一、查看发行版信息文件&#xff1a; CentOS&…

Prism导航入门学习笔记

首先创建一个空的Prism项目 在View文件夹中创建一个UserControl的A界面&#xff0c;再在ViewModel中创建一个AViewModel的类 在主页面中创建Button按钮&#xff0c;使用Command属性&#xff0c;指向导航命令的方法&#xff0c;CommandParameter指向导航的页面 <Grid><…

【Java】画心形图形

开始看到的是这个爱心图形&#xff0c;挺好看的&#xff08;感谢这些前端巨佬&#xff09;&#xff1a; HTML流光爱心_爱心代码html-CSDN博客 本来想着自己看下这个源代码能不能实现&#xff0c;看了下源代码其实非常复杂。 在看代码的过程中发现&#xff0c;源代码里边给出…

多线程(二):创建线程关键属性终止线程

目录 1、run & start 2、Thread类常见的属性和方法 2.1 构造方法 2.2 属性 3、后台进程 & 前台进程 4、后台线程的判断和设定——isDaemon & setDaemon 5、线程是否存活——isAlive 6、终止一个线程 6.1 lambda变量捕获 6.2 currentThread & isInterr…

使用three.js 实现蜡烛效果

使用three.js 实现蜡烛效果 import * as THREE from "three" import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"var scene new THREE.Scene(); var camera new THREE.PerspectiveCamera(60, window.innerWidth / window.in…

【opengl学习】opengl的compute shader

目的 opengl虽然老&#xff0c;但是算上opengl es&#xff0c;应该是应用最广泛的显卡api。用compute shader做计算&#xff0c;可以一定程度上摆脱N卡的限制&#xff0c;也摆脱windows和linux&#xff0c;mac等平台的限制。 计算着色器应该没有完全榨干硬件的性能&#xff0c…

CUDA - 如何让线程和内存对应

前提&#xff1a; 本文的目的就是设置的程序中&#xff0c;每个线程可以负责一个单独的计算任务。帮助学习和理解线程是如何组织的。 本文处理一个二维数据的加法。 数据在内存中的存储 以线性、行为主的方式存储。 例如&#xff0c;一个16*8的一维数组&#xff0c;在内存…

站在用户视角审视:以太彩光与PON之争

作者:科技作家-郑凯 园区,是企业数字化转型的“中心战场”。 云计算、大数据、人工智能等数智化技术在园区里“战火交织”;高清视频、协同办公,智慧安防等大量创新应用产生的海量数据在园区内“纵横驰骋”;加上大量的IOT和智能化设备涌入“战场”,让园区网络面对着难以抵御的…