Timing Text of Android Custom View

foreword

  In Android development, there are often some timing operations, such as countdown when receiving verification codes, stopwatch timing, etc., so I have an idea to write a custom View, the rendering of this article.

insert image description here

text

  So now we change our ideas into reality. This custom View is relatively simple. Let's see how to write it. First of all, we still EasyViewadd it in .

1. XML style

  According to the rendering above, we first determine the attribute style in XML, and add the following code in attrs.xml:

    <!--计时文字-->
    <declare-styleable name="TimingTextView">
        <!--倒计时-->
        <attr name="countdown" format="boolean" />
        <!--时间最大值-->
        <attr name="max" format="integer" />
        <!--时间单位,时:h,分:m,秒:s-->
        <attr name="unit">
            <enum name="h" value="1" />
            <enum name="m" value="2" />
            <enum name="s" value="3" />
        </attr>
    </declare-styleable>

  The timing text here currently has 3 attributes. The first boolean is used to determine whether it is timing or countdown, the second is the maximum time, and the third is the time unit: hours, minutes, and seconds.

2. Construction method

  I said before that there are three ways to customize View, one is to inherit View, one is to inherit the existing View, and the other is to inherit ViewGroup, then today’s timing text, we can inherit the existing View, do this The purpose is to allow us to reduce a certain amount of workload and focus on the function. Next, we com.llw.easyviewcreate a new TimingTextViewclass under the package, and the code inside is as follows:

public class TimingTextView extends MaterialTextView {
    
    

    /**
     * 时间单位
     */
    private int mUnit;
    /**
     * 计时最大值
     */
    private int mMax;
    /**
     * 是否倒计时
     */
    private boolean mCountDown;
    private int mTotal;
    /**
     * 是否计时中
     */
    private boolean mTiming;

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

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

    public TimingTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
        @SuppressLint("CustomViewStyleable")
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TimingTextView);
        mCountDown = typedArray.getBoolean(R.styleable.TimingTextView_countdown, false);
        mMax = typedArray.getInteger(R.styleable.TimingTextView_max, 60);
        mUnit = typedArray.getInt(R.styleable.TimingTextView_unit, 3);
        typedArray.recycle();
    }
}

  Because of the timing, we need a timing monitor, which is mainly used to call at the end. You com.llw.easyviewcan create a new TimingListenerinterface below, the code is as follows:

public interface TimingListener {
    
    
    void onEnd();
}

3. API method

Next, add some API methods and variables in TimingTextView, first increase the variables:

    private TimingListener listener;
    private CountDownTimer countDownTimer;

Then add the API method:

    /**
     * 设置时间单位
     *
     * @param unit 1,2,3
     */
    public void setUnit(int unit) {
    
    
        if (unit <= 0 || unit > 3) {
    
    
            throw new IllegalArgumentException("unit value can only be between 1 and 3");
        }
        mUnit = unit;
    }

    /**
     * 设置最大时间值
     *
     * @param max 最大值
     */
    public void setMax(int max) {
    
    
        mMax = max;
    }

    /**
     * 设置是否为倒计时
     *
     * @param isCountDown true or false
     */
    public void setCountDown(boolean isCountDown) {
    
    
        mCountDown = isCountDown;
    }

    public void setListener(TimingListener listener) {
    
    
        this.listener = listener;
    }

    public boolean isTiming() {
    
    
        return mTiming;
    }

    /**
     * 开始
     */
    public void start() {
    
    
        switch (mUnit) {
    
    
            case 1:
                mTotal = mMax * 60 * 60 * 1000;
                break;
            case 2:
                mTotal = mMax * 60 * 1000;
                break;
            case 3:
                mTotal = mMax * 1000;
                break;
        }
        if (countDownTimer == null) {
    
    
            countDownTimer = new CountDownTimer(mTotal, 1000) {
    
    
                @Override
                public void onTick(long millisUntilFinished) {
    
    
                    int time = 0;
                    if (mCountDown) {
    
    
                        time = (int)  (millisUntilFinished / 1000);
                        setText(String.valueOf(time));
                    } else {
    
    
                        time = (int) (mTotal / 1000 - millisUntilFinished / 1000);
                    }
                    setText(String.valueOf(time));
                }

                @Override
                public void onFinish() {
    
    
                    //倒计时结束
                    end();
                }
            };
            mTiming = true;
            countDownTimer.start();
        }

    }

    /**
     * 计时结束
     */
    public void end() {
    
    
        mTotal = 0;
        mTiming = false;
        countDownTimer.cancel();
        countDownTimer = null;
        if (listener != null) {
    
    
            listener.onEnd();
        }
    }

The code is still very simple. Believe it or not, this custom View is finished, but there may be some problems. I put all the code of the custom View under a library, and then build this library into an aar, and then upload it to mavenCentral()middle.

4. Use

  Then we modify activity_main.xml, the code is as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <com.easy.view.MacAddressEditText
        android:id="@+id/mac_et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:boxBackgroundColor="@color/white"
        app:boxStrokeColor="@color/black"
        app:boxStrokeWidth="2dp"
        app:boxWidth="48dp"
        app:separator=":"
        app:textColor="@color/black"
        app:textSize="16sp" />

    <Button
        android:id="@+id/btn_mac"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="获取地址" />

    <com.easy.view.CircularProgressBar
        android:id="@+id/cpb_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:maxProgress="100"
        app:progress="10"
        app:progressbarBackgroundColor="@color/purple_500"
        app:progressbarColor="@color/purple_200"
        app:radius="80dp"
        app:strokeWidth="16dp"
        app:text="10%"
        app:textColor="@color/teal_200"
        app:textSize="28sp" />

    <Button
        android:id="@+id/btn_set_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="随机设置进度" />

    <com.easy.view.TimingTextView
        android:id="@+id/tv_timing"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="计时文字"
        android:textColor="@color/black"
        android:textSize="32sp"
        app:countdown="false"
        app:max="60"
        app:unit="s" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:gravity="center"
        android:orientation="vertical">

        <CheckBox
            android:id="@+id/cb_flag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="计时" />

        <Button
            android:id="@+id/btn_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="开始" />
    </LinearLayout>
</LinearLayout>

The preview effect is shown in the figure below:

insert image description here
Let's go back to MainActivity and onCreate()add the following code to the method:

        //计时文本操作
        TimingTextView tvTiming = findViewById(R.id.tv_timing);
        CheckBox cbFlag = findViewById(R.id.cb_flag);
        Button btnStart = findViewById(R.id.btn_start);
        tvTiming.setListener(new TimingListener() {
    
    
            @Override
            public void onEnd() {
    
    
                tvTiming.setText("计时文字");
                btnStart.setText("开始");
            }
        });
        cbFlag.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    
    
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    
    
                cbFlag.setText(isChecked ? "倒计时" : "计时");
            }
        });
        //计时按钮点击
        btnStart.setOnClickListener(v -> {
    
    
            if (tvTiming.isTiming()) {
    
    
                //停止计时
                tvTiming.end();
                btnStart.setText("开始");
            } else {
    
    
                tvTiming.setMax(6);
                tvTiming.setCountDown(cbFlag.isChecked());
                tvTiming.setUnit(3);//单位 秒
                //开始计时
                tvTiming.start();
                btnStart.setText("停止");
            }
        });

Let's run it and see:

insert image description here

Five, source code

If it is helpful to you, you may wish to Star or Fork, the mountains are high and the waters are long, and there will be a period later~

Source address: EasyView

Guess you like

Origin blog.csdn.net/qq_38436214/article/details/130083055