android——自定义加载按钮LoadingButton

news2024/10/7 20:32:56

方式一

效果图:

 

 

simpleButton类代码:

package com.oneway.demo.navcontroller.view;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.oneway.demo.navcontroller.R;


public class SimpleLoadingButton extends View {

    private int textColor;
    private int backgroundNormal;
    private float textSize;
    private String content;
    private Bitmap bitmap;
    private int default_padding;
    private int paddingBottom;
    private int paddingLeft;
    private int paddingTop;
    private int paddingRight;
    private Paint paintRect;
    private Paint paintTxt;
    private RectF rect;
    private float txtHeight;
    private Matrix matrix;
    private ObjectAnimator animator;
    private int mViewWidth;
    private int mViewHeight;
    private int STATE_NORMAL = 0;
    private int STATE_LOADING = 1;
    private int STATE_COMPLETED = 2;
    private int state = STATE_NORMAL;
    private String loadingTxt;
    private String contentNormal;
    private float corners;
    private int backgroundPressed;

    public SimpleLoadingButton(Context context) {
        this(context, null, 0);
    }

    public SimpleLoadingButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleLoadingButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initData(context);
    }

    /**
     * 方法描述:初始化属性值
     *
     * @param context 上下文
     * @param attrs   属性集合
     */
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleLoadingButton);
        backgroundNormal = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_normal,
                Color.parseColor("#3A96FF"));
        backgroundPressed = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_pressed,
                Color.parseColor("#1E90FF"));
//        Log.e("Custom", "background===" + background);
//        if (background >= TypedValue.TYPE_FIRST_COLOR_INT &&
//                background <= TypedValue.TYPE_LAST_COLOR_INT){


        textColor = typeArray.getColor(R.styleable.SimpleLoadingButton_button_text_color, Color.WHITE);
        textSize = typeArray.getDimension(R.styleable.SimpleLoadingButton_button_text_size, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
        contentNormal = typeArray.getString(R.styleable.SimpleLoadingButton_button_text);
        loadingTxt = typeArray.getString(R.styleable.SimpleLoadingButton_button_loading_text);
        corners = typeArray.getDimension(R.styleable.SimpleLoadingButton_corners, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics()));
        typeArray.recycle();
    }

    private void initData(Context context) {
        if (contentNormal != null) {
            content = contentNormal;
        } else {
            content = "";
        }

        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.loading);

        default_padding = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 22, getResources().getDisplayMetrics());

        paddingBottom = getPaddingBottom();
        paddingLeft = getPaddingLeft();
        paddingTop = getPaddingTop();
        paddingRight = getPaddingRight();

        //矩形画笔
        paintRect = new Paint();
        paintRect.setColor(backgroundNormal);
        paintRect.setAntiAlias(true);
        paintRect.setStyle(Paint.Style.FILL);

        //矩形对象
        rect = new RectF();

        //文字画笔
        paintTxt = new Paint();
        paintTxt.setColor(textColor);
        paintRect.setAntiAlias(true);
        paintTxt.setTextAlign(Paint.Align.CENTER);
        paintTxt.setTextSize(textSize);
        txtHeight = (float) getTxtHeight(paintTxt);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measureWidth = measureWidth(widthMeasureSpec);
        int measureHeight = measureHeight(heightMeasureSpec);
        initRect(measureWidth, measureHeight);
        setMeasuredDimension(measureWidth, measureHeight);
    }

    /**
     * 方法描述:矩形对象初始化
     */
    private void initRect(int measureWidth, int measureHeight) {
        rect.left = 0;
        rect.top = 0;
        rect.right = measureWidth;
        rect.bottom = measureHeight;
    }

    private int measureWidth(int measureSpec) {
        int width;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            width = specSize;
        } else {
            width = (int) paintTxt.measureText(content) + paddingLeft + paddingRight;
            if (specMode == MeasureSpec.AT_MOST) {
                width = Math.min(width, specSize);
            }
        }
        return width;
    }

    private int measureHeight(int measureSpec) {
        int height = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            height = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            height = (int) txtHeight + paddingTop + paddingBottom + default_padding;
        }
        return height;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRoundRect(rect, corners, corners, paintRect);
        if (state == STATE_NORMAL) {
            canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
                    rect.height() / 2 + txtHeight / 3, paintTxt);
        }
        if (state == STATE_LOADING) {
            canvas.translate(mViewWidth / 2, mViewHeight / 2);// 旋转的位置
            matrix.preTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2);//旋转中心点
            canvas.drawBitmap(bitmap, matrix, null);
        }
        if (state == STATE_COMPLETED) {
            canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
                    rect.height() / 2 + txtHeight / 3, paintTxt);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (listener == null) {
            return true;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (loadingTxt == null) {
                    content = "";
                } else {
                    content = loadingTxt;
                }
                paintRect.setColor(backgroundPressed);
                state = STATE_NORMAL;
                postInvalidate();
                break;
            case MotionEvent.ACTION_UP:
                paintRect.setColor(backgroundNormal);
                startAnim();
                state = STATE_LOADING;
                postInvalidate();
                listener.onLoadingClick(this);
                break;
        }
        return true;
    }

    /**
     * 方法描述:加载完成以后让SimpleLoadingButton复位
     */
    public void setCompleted() {
        content = contentNormal;
        state = STATE_COMPLETED;
        cancelAnim();
        postInvalidate();
    }


    /**
     * 方法描述:获取文本字符的高度
     *
     * @param mPaint 画文本字符的画笔
     * @return 文本字符的高度
     */
    public double getTxtHeight(Paint mPaint) {
        Paint.FontMetrics fm = mPaint.getFontMetrics();
        return Math.ceil(fm.descent - fm.ascent);
    }

    /**
     * 方法描述:开启动画
     */
    private void startAnim() {
        if (animator == null) {
            initAnimator();
            animator.start();
            return;
        }
        if (!animator.isRunning()) {
            animator.start();
        }
    }

    /**
     * 方法描述:取消动画
     */
    private void cancelAnim() {
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
    }

    @SuppressLint("ObjectAnimatorBinding")
    private void initAnimator() {
        matrix = new Matrix();
        animator = ObjectAnimator.ofFloat(matrix, "rotation", 0, 360);
        animator.setDuration(1000);
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                matrix.setRotate((float) animation.getAnimatedValue());
                invalidate();
            }
        });
    }

    private LoadingListener listener;

    public void setLoadingListener(LoadingListener loginClickListener) {
        this.listener = loginClickListener;
    }

    public interface LoadingListener {
        void onLoadingClick(SimpleLoadingButton view);
    }
}

value文件夹里面的attrs.xml代码为:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SimpleLoadingButton">
        <attr name="button_background_color_normal" format="color" />
        <attr name="button_background_color_pressed" format="color" />
        <attr name="button_text" format="string" />
        <attr name="button_text_color" format="color" />
        <attr name="button_text_size" format="dimension" />
        <attr name="button_loading_text" format="string" />
        <attr name="corners" format="dimension" />
    </declare-styleable>
</resources>

loading.png图标为:

在activity的xml里面添加代码:

<com.oneway.demo.navcontroller.view.SimpleLoadingButton
        android:id="@+id/simple_loading_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        app:button_background_color_normal="#3A96FF"
        app:button_background_color_pressed="#1E90FF"
        app:button_loading_text="登录中..."
        app:button_text="登录"
        app:button_text_color="#ffffff"
        app:button_text_size="18sp"
        app:corners="8dp"
        tools:ignore="MissingConstraints" />

 最后,开始调用findviewbyid拿到SimpleLoadingButton控件,调用setLoadingListener方法

 加载结束调用setCompleted方法复位

方式二

点击前效果:

 点击后效果:

 

LoadingButton代码:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;

/**
 *
 */
public class LoadingButton extends androidx.appcompat.widget.AppCompatButton {
    private Context context;

    // 开始Loading时的回调
    private OnStartListener startListener;

    // 结束Loading时的回调
    private OnFinishListener finishListener;

    // 开始和结束Loading时的回调
    private OnLoadingListener listener;

    // Loading动画旋转周期
    private int rotateDuration = 1000;

    // 按钮缩成Loading动画的时间
    private int reduceDuration = 350;

    // Loading旋转动画控制器
    private Interpolator rotateInterpolator;

    // 按钮缩成Loading动画的控制器
    private Interpolator reduceInterpolator;

    private int width;
    private int height;

    private String text;

    // 是否在Loading中
    private boolean isLoading = false;

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

    public LoadingButton(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public LoadingButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        this.context = context;

        setGravity(Gravity.CENTER);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (width == 0) width = getMeasuredWidth();
        if (height == 0) height = getMeasuredHeight();
    }

    /**
     * 播放按钮缩成Loading的动画
     */
    private void showStartLoadAnimation() {
        ValueAnimator animator = new ValueAnimator().ofInt(width, height);
        animator.setDuration(reduceDuration);
        if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                getLayoutParams().width = (int) animation.getAnimatedValue();
                requestLayout();
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
                setEnabled(false);
                text = getText().toString();
                setText("");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                showLoadingAnimation();
            }
        });
        animator.start();
    }

    /**
     * 播放Loading动画
     */
    private void showLoadingAnimation() {
        RotateAnimation animation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setDuration(rotateDuration);
        animation.setInterpolator(rotateInterpolator != null ? rotateInterpolator : new LinearInterpolator());
        animation.setRepeatCount(-1);
        setBackgroundDrawable(context.getResources().getDrawable(R.drawable.circle_loading));
        if (startListener != null) {
            startListener.onStart();
        } else if (listener != null) {
            listener.onStart();
        }
        startAnimation(animation);
        isLoading = true;
    }

    /**
     * 播放Loading拉伸成按钮的动画
     */
    private void showFinishLoadAnimation() {
        ValueAnimator animator = new ValueAnimator().ofInt(height, width);
        animator.setDuration(reduceDuration);
        if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                getLayoutParams().width = (int) animation.getAnimatedValue();
                requestLayout();
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
                setEnabled(false);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                setText(text);
                setEnabled(true);
                if (finishListener != null) {
                    finishListener.onFinish();
                } else if (listener != null) {
                    listener.onFinish();
                }
            }
        });
        animator.start();
        isLoading = false;
    }

    /**
     * 开始Loading
     */
    public void startLoading() {
        if (!isLoading) {
            clearAnimation();
            showStartLoadAnimation();
        }
    }

    /**
     * 开始Loading
     *
     * @param listener Loading开始时的回调
     */
    public void startLoading(OnStartListener listener) {
        if (!isLoading) {
            this.startListener = listener;
            clearAnimation();
            showStartLoadAnimation();
        }
    }

    /**
     * 结束Loading
     */
    public void finishLoading() {
        if (isLoading) {
            clearAnimation();
            showFinishLoadAnimation();
        }
    }

    /**
     * 结束Loading
     *
     * @param listener Loading结束时的回调
     */
    public void finishLoading(OnFinishListener listener) {
        if (isLoading) {
            this.finishListener = listener;
            clearAnimation();
            showFinishLoadAnimation();
        }
    }

    /**
     * 设置Loading开始和结束时的回调接口
     *
     * @param listener
     */
    public void setOnLoadingListener(OnLoadingListener listener) {
        this.listener = listener;
    }

    /**
     * 设置按钮缩成Loading动画的时间
     *
     * @param reduceDuration 时间,单位毫秒
     */
    public void setReduceDuration(int reduceDuration) {
        this.reduceDuration = reduceDuration;
    }

    /**
     * 设置Loading动画旋转周期
     *
     * @param rotateDuration 旋转周期,单位毫秒
     */
    public void setRotateDuration(int rotateDuration) {
        this.rotateDuration = rotateDuration;
    }

    /**
     * 获取是否正在Loading
     *
     * @return
     */
    public boolean isLoading() {
        return isLoading;
    }

    /**
     * 设置Loading旋转动画控制器
     *
     * @param rotateInterpolator
     */
    public void setRotateInterpolator(Interpolator rotateInterpolator) {
        this.rotateInterpolator = rotateInterpolator;
    }

    /**
     * 按钮缩成Loading动画的控制器
     *
     * @param reduceInterpolator
     */
    public void setReduceInterpolator(Interpolator reduceInterpolator) {
        this.reduceInterpolator = reduceInterpolator;
    }

    /**
     * Loading开始时的回调接口
     */
    public interface OnStartListener {
        void onStart();
    }

    /**
     * Loading结束时的回调接口
     */
    public interface OnFinishListener {
        void onFinish();
    }

    /**
     * Loading开始和结束时的回调接口
     */
    public interface OnLoadingListener {
        void onStart();

        void onFinish();
    }
}

button_main_color_up.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <corners android:radius="20dp" />

    <solid android:color="#45a8ca" />

    <gradient
        android:endColor="#45a8ca"
        android:startColor="#6fd1e7" />

</shape>

button_main_color_down.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <corners android:radius="20dp" />

    <solid android:color="#45a8aa" />

    <gradient
        android:endColor="#45a8aa"
        android:startColor="#6fd1c7" />

</shape>

button_main_color_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/button_main_color_up" android:state_pressed="false"></item>
    <item android:drawable="@drawable/button_main_color_down" android:state_pressed="true"></item>

</selector>

circle_loading.xml代码

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:innerRadius="18dp"
    android:shape="ring"
    android:thickness="2dp"
    android:useLevel="false">

    <solid android:color="#45a8ca" />

    <gradient
        android:endColor="#45a8ca"
        android:startColor="#0000"
        android:type="sweep" />

</shape>

在activity.xml里面的代码为:

<com.oneway.demo.loadingbutton.LoadingButton
        android:id="@+id/load_btn"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:background="@drawable/button_main_color_selector"
        android:text="CLICK"
        android:textColor="#ffffff"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

在activity里的代码为(开始加载):

findViewById<LoadingButton>(R.id.load_btn).setOnClickListener {
            (it as LoadingButton).startLoading()
        }

结束加载:finishLoading

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

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

相关文章

基于TCP的DNS传输:操作要求

本文档更新了RFC 1123和RFC 1536。本文档要求将允许DNS消息在Internet上通过TCP传输的操作实践作为当前最佳实践。此操作要求与RFC 7766中的实施要求一致。TCP的使用包括基于未加密TCP的DNS以及加密的TLS会话。该文件还考虑了这种形式的DNS通信的后果&#xff0c;以及在不支持当…

腾讯T3整理分享的LeetCode算法小抄完整文档

前言 本文⽬前可以⼿把⼿带你解决 110 道 LeetCode 算法问题&#xff0c;⽽且在不断更新&#xff0c;全部基于 LeetCode 的题⽬&#xff0c;涵盖了所有题型和技巧。 目录 主要内容 ⽬前已包含的 114 道题⽬教程如下&#xff1a; 1.两数之和 10.正则表达式匹配 100.相同的树 …

vue中的transition学习

transition 会在一个元素或组件进入和离开 DOM 时应用动画。他可以将进入和离开的动画应用通过默认插槽传递给它的元素或者组件上 transitionGroup 会在一个 v-for 列表中的元素或组件被插入&#xff0c;移动&#xff0c;或移除时应用动画 <Transition> 组件 进入或者…

[附源码]java毕业设计研究生管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

GoLand 文件增加头部注释

一 背景 为了统一规范,决定在项目中要增加注释,包括文件的头部注释以及函数方法的注释。函数方法的注释好说,文件头部注释这个搞了半天(搞完后才发现真的很容易),记录下自己搞得过程,方便其他人。 二 设置头部注释的步骤 我的系统环境是Macos,这篇文章针对的Mac电…

mitmproxy

我们经常了解到的抓包工具有wireshark、fiddler、charles等&#xff0c;mitmproxy也是一个代理工具&#xff0c;突出的优点是可以命令行方式或脚本的方式进行代理&#xff0c;可以对请求数据进行二次开发&#xff08;二次定制&#xff09; 官网&#xff1a;https://mitmproxy.o…

10 张图解 K8S CNI Calico 网络模型原理与功能实战

一、概述 Calico 是一个联网和网络策略供应商。Calico 支持一套灵活的网络选项&#xff0c;因此你可以根据自己的情况选择最有效的选项&#xff0c;包括非覆盖和覆盖网络&#xff0c;带或不带 BGP。Calico 使用相同的引擎为主机、Pod 和&#xff08;如果使用 Istio 和 Envoy&am…

Nginx:配置

文章目录1、Nginx 工作原理2、Nginx 安装启动2.1、安装2.2、启动3、配置文件3.1、块配置3.2、代理 & 负载均衡3.2.1、代理正向代理反向代理3.2.2、负载均衡3.3、Nginx 缓存3.4、Nginx 限流4、http 配置使用4.1、配置结构4.2、配置命令4.2.1、设置配置命令4.2.2、设置回调方…

你也还在找程序员外包平台吗?有这几个就足够了!

大家都知道&#xff0c;如果程序员想在工作之余赚一点外快的话&#xff0c;接外包是所有兼职赚钱之中来钱比较快的一种。但是要找到一些比较靠谱的&#xff0c;能够经常使用的接外包平台&#xff0c;似乎是一件费时又费力的事情。 接下来就为大家推荐几个比较好的程序员接外包的…

Python_数据容器_列表list

一、数据容器入门 使用场景&#xff1a;批量存储、批量使用多份数据 Python中的数据容器&#xff1a; 一种可以容纳多份数据的数据类型&#xff0c;容纳的每一份数据称之为一个元素。每一个元素&#xff0c;可以是任意类型的数据&#xff0c;如字符串、数字、布尔等。 总结&…

Windows下的RabbitMQ 安装

1.到rabbitmq官网下载安装程序 Messaging that just works — RabbitMQ 1.1 我选择的事RabbitMQ 3.11.3 1.2 点击链接后进入下面的界面 1.3 继续点击RabbitMQ 3.11.3 release 链接 Release RabbitMQ 3.11.3 rabbitmq/rabbitmq-server GitHub 1.4 在页面最下面可以看到下…

葡萄糖-聚乙二醇-四嗪/叶酸/多巴胺 Glucose-PEG-TZ/FA/Dopamine

葡萄糖-聚乙二醇-四嗪/叶酸/多巴胺 Glucose-PEG-TZ/FA/Dopamine 叶酸是一种水溶性维生素&#xff0c;分子式是C19H19N7O6。因绿叶中含量十分丰富而得名&#xff0c;又名蝶酰谷氨酸。在自然界中有几种存在形式&#xff0c;其母体化合物是由蝶啶、对氨基苯甲酸和谷氨酸3种成分结…

购物车案例的实现

最终效果&#xff1a; 1.计算属性 用于计算最终价格&#xff0c;对此计算使用计算属性最佳 原理是遍历books中的每一个属性&#xff0c;价格*数量 computed:{totalPrice(){let totalPrice0// 1.普通的for循环// for (let i0;i<this.books.length;i)// {// totalPriceth…

java+jsp+servlet+mysql高速公路事故管理(交通管理)系统

项目介绍&#xff1a; 一个使用javamysql开发的jspservlet高速公路事故管理系统。 功能主要包括&#xff0c;事故管理&#xff08;可以上传事故照片&#xff09;、车辆信息管理、车主信息管理、违法信息管理、可以按照柱状图&#xff08;饼状图、折线图&#xff09;分析事故…

为什么你需要Twitter群控

爆粉必备 Twitter爆粉的原理是什么&#xff1f; Twitter爆粉怎么实现呢&#xff1f;你先关注别人&#xff0c;然后和人家互动&#xff0c;比如发私信、点赞、评论转发帖子&#xff0c;让别人看到你并回关你&#xff0c;一段时间不回关&#xff0c;你就取消对他们的关注&#…

html中的固定定位的用法

文章目录 前言 一、固定定位的理解&#xff1f; 二、固定定位用在哪里&#xff1f; 1、给大家分享一个案例 2、代码编写 1、先准备一个小案例 2、效果如下&#xff0c;浏览器左上角有个盒子&#xff0c;右边有滚动条 3、我想让他像我们的csdn一样&#xff0c;这个盒子固定在右下…

科技连接美好未来 | 美格智能5G FWA解决方案持续推进

近年来&#xff0c;5G网络在全球范围的全面推广和普及&#xff0c;促使市场对高速宽带连接的需求持续增长&#xff0c;5G FWA作为低成本的网络接入选项&#xff0c;或将成为5G市场新一代的杀手级应用。 5G的持续推动&#xff0c;促使FWA出货量呈现出高速增长趋势。就2020年&…

学了C++能做什么?

相信很多人接触编程都是源于大学期间的那堂C语言程序编程&#xff0c;但是这门课却只告诉了你编程语言是什么&#xff0c;却没告诉你要怎么去熟练掌握编程。所以&#xff0c;不可避免的是许多人在毕业前夕才发现虽然学会了C&#xff0c;但是好像却不知道能干什么&#xff0c;能…

[附源码]java毕业设计学生考试成绩分析系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

浅学Go下的ssti漏洞问题

前言 作为强类型的静态语言&#xff0c;golang的安全属性从编译过程就能够避免大多数安全问题&#xff0c;一般来说也唯有依赖库和开发者自己所编写的操作漏洞&#xff0c;才有可能形成漏洞利用点&#xff0c;在本文&#xff0c;主要学习探讨一下golang的一些ssti模板注入问题…