Как ограничить представление (TextView) для текущего прогресса progressBar? - PullRequest
1 голос
/ 13 января 2020

У меня есть проект, над которым я работаю, в этом проекте я использую progressBars в качестве графика баров,

, то есть: я получаю список элементов, затем я проверяю, какой элемент имеет максимальное значение, и я устанавливаю это максимальное значение равным максимальному прогрессу всех индикаторов прогресса (элементов),

, тогда я хотел бы показать значение каждого элемента (прогресс), но я хочу прикрепить его к ход выполнения указанного элемента c, другими словами, я хотел бы показывать значение прогресса в конце каждого прогресса каждого хода выполнения,

Пример: максимальный прогресс 29, не обращайте внимания на процентное значение или метки ниже

a busy cat

Мне удалось сделать вертикальные индикаторы прогресса после некоторого поиска, но эту проблему я пытаюсь решить,

Есть ли способ прикрепить что-нибудь к прогрессу индикатора выполнения? Есть ли способ ссылаться на прогресс в xml? (Максимальное значение и прогресс различных элементов известны только во время выполнения и остаются неизменными c после)

thx.

1 Ответ

1 голос
/ 13 января 2020

Реализация этого с использованием обычного индикатора выполнения и вертикального перемещения делает все слишком сложным. Поэтому мое решение состоит в том, чтобы создать собственное представление, которое состоит из представления с фоном ClipDrawable для прогресса и TextView для метки.

Полный код:

LabeledVerticalProgressBar. java

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;

import androidx.constraintlayout.widget.ConstraintLayout;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID;

public class LabeledVerticalProgressBar extends ConstraintLayout {
    private TextView textView;
    private View progressView;

    private Drawable progressDrawable;
    private float min;
    private float max;
    private float progress;
    private int labelTextAppearanceId;
    private boolean isLabelAbove = true;
    private int numDecimals;
    private String unit = "";

    private int height;

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

    private void init(AttributeSet attrs) {
        initViews();
        initAttributes(attrs);
        initProgress();
        initLabel();
    }

    private void initViews() {
        progressView = new View(getContext());
        progressView.setId(View.generateViewId());
        LayoutParams progressParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
        progressParams.topToTop = PARENT_ID;
        progressParams.bottomToBottom = PARENT_ID;
        progressParams.startToStart = PARENT_ID;
        progressParams.endToEnd = PARENT_ID;
        progressView.setLayoutParams(progressParams);

        textView = new TextView(getContext());
        int padding = (int)(4 * getResources().getDisplayMetrics().density);
        textView.setPadding(padding, padding, padding, padding);
        LayoutParams textParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
        textParams.startToStart = progressView.getId();
        textParams.endToEnd = progressView.getId();
        textParams.bottomToBottom = progressView.getId();
        textView.setLayoutParams(textParams);

        addView(progressView);
        addView(textView);

        setClipChildren(false);
        setClipToPadding(false);
    }

    private void initAttributes(AttributeSet attrs) {
        TypedArray a = getContext().getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.LabeledVerticalProgressBar,
                0, 0);
        try {
            progressDrawable = a.getDrawable(R.styleable.LabeledVerticalProgressBar_progress_drawable);
            min = a.getFloat(R.styleable.LabeledVerticalProgressBar_min, 0);
            max = a.getFloat(R.styleable.LabeledVerticalProgressBar_max, 100);
            progress = a.getFloat(R.styleable.LabeledVerticalProgressBar_progress, 0);

            initTextAppearance(a);

            int labelPos = a.getInt(R.styleable.LabeledVerticalProgressBar_label_position, 0);
            if (labelPos == 1) {
                isLabelAbove = false;
            }
            numDecimals = a.getInt(R.styleable.LabeledVerticalProgressBar_num_decimals, 0);
            unit = a.getString(R.styleable.LabeledVerticalProgressBar_unit);

            if (min >= max) {
                throw new IllegalArgumentException("max should be greater than min");
            }
            clampProgress();
        } finally {
            a.recycle();
        }
    }

    private void initTextAppearance(TypedArray a) {
        /*TypedValue styleId = new TypedValue();
        boolean resolved = getContext().getTheme().resolveAttribute(R.styleable.LabeledVerticalProgressBar_label_text_appearance,
                styleId, true);
        if (resolved) {
            labelTextAppearanceId = styleId.data;
        } else {
            labelTextAppearanceId = -1;
        }*/
        ColorStateList color = a.getColorStateList(R.styleable.LabeledVerticalProgressBar_label_text_color);
        int size = a.getDimensionPixelSize(R.styleable.LabeledVerticalProgressBar_label_text_size, -1);
        int style = a.getInt(R.styleable.LabeledVerticalProgressBar_label_text_style, -1);
        Drawable background = a.getDrawable(R.styleable.LabeledVerticalProgressBar_label_background);

        if (color != null) {
            textView.setTextColor(color);
        }
        if (size != -1) {
            textView.setTextSize(size);
        }
        if (style != -1) {
            switch (style) {
                case 0: textView.setTypeface(textView.getTypeface(), Typeface.NORMAL); break;
                case 1: textView.setTypeface(textView.getTypeface(), Typeface.BOLD); break;
                case 2: textView.setTypeface(textView.getTypeface(), Typeface.ITALIC); break;
                case 3: textView.setTypeface(textView.getTypeface(), Typeface.BOLD_ITALIC); break;
            }
        }
        if (background != null) {
            textView.setBackground(background);
        }
    }

    private void initProgress() {
        if (progressDrawable == null) {
            progressDrawable = initDefaultProgressDrawable();
        }
        updateProgressView();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        height = progressView.getMeasuredHeight();
        initLabel();
        if (isLabelAbove) {
            // Add top space for label when progress is at max.
            setPadding(0, textView.getMeasuredHeight(), 0, 0);
        }
        super.onLayout(changed, left, top, right, bottom);
    }

    private void initLabel() {
        updateLabel();
        /*if (labelTextAppearanceId != -1) {
            TextViewCompat.setTextAppearance(textView, labelTextAppearanceId);
        }*/
    }

    public void setProgress(float progress) {
        this.progress = progress;
        clampProgress();
        progressView.getBackground().setLevel(computeLevel());
        updateLabel();
    }

    public void setProgress(final float progress, boolean animate, int duration) {
        if (animate) {
            float end = clampProgress(progress);
            float start = this.progress;
            ValueAnimator animator = ValueAnimator.ofFloat(start, end);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    LabeledVerticalProgressBar.this.progress = (float) animation.getAnimatedValue();
                    progressView.getBackground().setLevel(computeLevel());
                    updateLabel();
                }
            });
            animator.setDuration(duration);
            animator.start();

        } else {
            setProgress(progress);
        }
    }

    public void setMax(float max) {
        this.max = max;
        if (min >= max) {
            throw new IllegalArgumentException("max should be greater than min");
        }
        setProgress(progress);
    }

    public void setMin(float min) {
        this.min = min;
        if (min >= max) {
            throw new IllegalArgumentException("max should be greater than min");
        }
        setProgress(progress);
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    public void setProgressDrawableColor(int color) {
        progressDrawable = new ColorDrawable(color);
        updateProgressView();
    }

    public void setProgressDrawable(Drawable progressDrawable) {
        this.progressDrawable = progressDrawable;
        updateProgressView();
    }

    private void updateProgressView() {
        ClipDrawable clip = new ClipDrawable(progressDrawable, Gravity.BOTTOM, ClipDrawable.VERTICAL);
        progressView.setBackground(clip);
        clip.setLevel(computeLevel());
    }

    private void updateLabel() {
        float translation = computeLabelTranslation();
        if (isLabelAbove) {
            textView.setTranslationY(translation);
        } else {
            if (-translation > textView.getMeasuredHeight()) {
                textView.setTranslationY(translation + textView.getMeasuredHeight());
            } else {
                textView.setTranslationY(0);
            }
        }
        String progressStr = String.format("%." + numDecimals + "f", progress) + unit;
        textView.setText(progressStr);
    }

    private int computeLevel() {
        float fraction = computeProgressFraction();
        return (int) (fraction * 10000);
    }

    private float computeLabelTranslation() {
        return -computeProgressFraction() * height;
    }

    private float computeProgressFraction() {
        clampProgress();
        return (progress - min) / (max - min);
    }

    private Drawable initDefaultProgressDrawable() {
        int colorAttr = getContext().getResources().getIdentifier("colorPrimary",
                "attr", getContext().getPackageName());
        TypedValue outValue = new TypedValue();
        getContext().getTheme().resolveAttribute(colorAttr, outValue, true);
        return new ColorDrawable(outValue.data);
    }

    private void clampProgress() {
        if (progress > max) {
            progress = max;
        } else if (progress < min) {
            progress = min;
        }
    }

    private float clampProgress(float progress) {
        if (progress > max) {
            return max;
        } else if (progress < min) {
            return min;
        } else {
            return progress;
        }
    }
}

attrs. xml

<resources>
    <declare-styleable name="LabeledVerticalProgressBar">
        <attr name="progress_drawable" format="reference|color"/>
        <attr name="min" format="float"/>
        <attr name="max" format="float"/>
        <attr name="progress" format="float"/>
        <attr name="label_text_appearance" format="reference"/>
        <attr name="label_text_color" format="color"/>
        <attr name="label_text_size" format="dimension"/>
        <attr name="label_text_style" format="enum">
            <enum name="normal" value="0"/>
            <enum name="bold" value="1"/>
            <enum name="italic" value="2"/>
            <enum name="bold_italic" value="3"/>
        </attr>
        <attr name="label_background" format="reference|color"/>
        <attr name="label_position" format="enum">
            <enum name="above" value="0"/>
            <enum name="below" value="1"/>
        </attr>

        <!--Number of displayed decimal places for label-->
        <attr name="num_decimals" format="integer"/>

        <attr name="unit" format="string"/>
    </declare-styleable>
</resources>

Использование:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <marabillas.loremar.bindtextviewandprogressbar.LabeledVerticalProgressBar
        android:id="@+id/progressBar"
        android:layout_width="80dp"
        android:layout_height="480dp"
        android:background="#ddd"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:progress_drawable="#6a0dad"
        app:label_text_color="#fff"
        app:label_text_size="24sp"
        app:label_text_style="bold"
        app:label_background="#4ccc"
        app:label_position="below"
        app:min="20"
        app:max="500"
        app:progress="20"
        app:num_decimals="0"
        app:unit="%"/>

</androidx.constraintlayout.widget.ConstraintLayout>
@Override
    protected void onStart() {
        super.onStart();
        final LabeledVerticalProgressBar progressBar = findViewById(R.id.progressBar);
        progressBar.setProgress(500, true, 3000);

        Handler handler = new Handler(Looper.getMainLooper());

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                progressBar.setProgressDrawableColor(Color.GREEN);
            }
        }, 2000);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                GradientDrawable gradient = new GradientDrawable();
                int color1 = Color.HSVToColor(new float[]{240f, 1f, 1f});
                int color2 = Color.HSVToColor(new float[]{240f, 1f, 0.5f});
                int[] colors = { color1, color2, color1};
                gradient.setColors(colors);
                gradient.setGradientType(GradientDrawable.LINEAR_GRADIENT);
                gradient.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
                progressBar.setProgressDrawable(gradient);

                progressBar.setMax(2000);
                progressBar.setProgress(4000);
                progressBar.setMin(1000);
                progressBar.setUnit("");
                progressBar.setProgress(1500, true, 3000);
            }
        }, 3000);
    }

Результаты:

enter image description here

Вы можете использовать setProgess(), чтобы установить прогресс без анимации или передать false в animate параметр.

На данный момент я не могу создать видимость текста для работы надписи .

Я думаю, что с помощью нескольких правок вы также можете сделать это по горизонтали.

...