Android 实现一个带有两个剪辑文本视图的进度条

Android implement a progressBar with two clip textview on it

我要实现一个带有两个剪辑文本视图的进度条。 就像是:

我用了一些技巧(使用paddingEnd/paddingStart、back/front textview来实现textview的剪辑效果)来实现它:

    // part of activity
    TextView leftFrontText;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        View view = View.inflate(this, R.layout.test_page_layout, containerLayout);

        View progressBar = view.findViewById(R.id.progress_bar);
        leftFrontText = view.findViewById(R.id.left_front_textview);

        int progress = 59;
        ValueAnimator va = ValueAnimator.ofFloat(0f, progress);
        int mDuration = 1000;
        va.setDuration(mDuration);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float)animation.getAnimatedValue();
                setViewWidth(progressBar, (int)value);
                setLeftFrontTextViewPadding((int)value);
            }
        });
//        va.addListener(new Animator.AnimatorListener() {
//            @Override
//            public void onAnimationStart(Animator animation) {
//
//            }
//
//            @Override
//            public void onAnimationEnd(Animator animation) {
//                setLeftFrontTextViewPadding(progress);
//            }
//
//            @Override
//            public void onAnimationCancel(Animator animation) {
//
//            }
//
//            @Override
//            public void onAnimationRepeat(Animator animation) {
//
//            }
//        });
        va.start();
    }

    private void setViewWidth(View view, int dp) {
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        layoutParams.width = ThemeUtil.dpToPx(this, dp);
        view.setLayoutParams(layoutParams);
    }

    private void setLeftFrontTextViewPadding(int progressBarDp) {

        int marginStart = ThemeUtil.dpToPx(TestPageActivity.this, 12);
        leftFrontText.post(new Runnable() {
            @Override
            public void run() {
                int textViewLength = leftFrontText.getWidth();
                int progressbarDistance = ThemeUtil.dpToPx(TestPageActivity.this, progressBarDp);
                if (textViewLength >= 0) {
                    int padding = marginStart + textViewLength - progressbarDistance;
                    leftFrontText.setPadding(0, 0, padding > 0 ? -padding : 0, 0);
                }
            }
        });

    }

布局为:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="28dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/rounded_corner_bg_for_cashlfow_homepage_category_cell"
    android:layout_marginStart="16dp"
    android:layout_marginEnd="16dp"
    >

    <TextView
        android:id="@+id/left_bottom_textview"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:gravity="center_vertical"
        android:text="Entertatinment"
        android:textSize="@dimen/main_text_size"
        android:maxLines="1"
        android:ellipsize="end"
        android:textColor="@color/grey1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="12dp"
        />

    <View
        android:id="@+id/progress_bar"
        android:layout_width="10dp"
        android:layout_height="match_parent"
        android:background="@drawable/rounded_corner_front_progreebar_homepage_category_cell"
        app:layout_constraintStart_toStartOf="parent"
        />

    <TextView
        android:id="@+id/left_front_textview"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:gravity="center_vertical|start"
        android:text="Entertatinment"
        android:textSize="@dimen/main_text_size"
        android:maxLines="1"
        android:ellipsize="end"
        android:textColor="@color/white"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="12dp"
        />

    <TextView
        android:id="@+id/right_bottom_amount_textview"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:gravity="center_vertical|end"
        android:text="[=12=] / [=12=]"
        android:textSize="@dimen/main_text_size"
        android:maxLines="1"
        android:textColor="@color/white"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="12dp"
        />

    <TextView
        android:id="@+id/right_front_amount_textview"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:gravity="center_vertical|end"
        android:text="[=12=] / [=12=]"
        android:textSize="@dimen/main_text_size"
        android:maxLines="1"
        android:textColor="@color/black1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="12dp"
        android:paddingStart="0dp"
        />

</android.support.constraint.ConstraintLayout>

当我运行这段代码时,几乎达到了我想要的效果。但它有一个问题。 Textview在做动画的时候一直在闪烁,当动画结束的时候,textview的颜色有时会变成全白。

我认为 setLeftFrontTextViewPaddingleftFrontText.post() 中可能有问题,比如我如何获取 textview 的宽度。但我不太确定。谁能告诉我正确的方法吗?或者任何其他更好的方法来实现这种进度条。

为什么不尝试这种方法并利用 ConstraintLayout 的力量作为您的进度条:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/parentview"
    android:layout_width="360dp"
    android:layout_height="28dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#ddddff"
    android:layout_marginStart="16dp"
    android:layout_marginEnd="16dp">

    <TextView
        android:id="@+id/left_bottom_textview"
        android:layout_width="180dp"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:text="Entertainment"
        android:maxLines="1"
        android:ellipsize="end"
        android:textColor="#404040"
        app:layout_constraintStart_toStartOf="parent"/>

    <TextView
        android:id="@+id/right_front_amount_textview"
        android:layout_width="180dp"
        android:layout_height="0dp"
        android:gravity="center_vertical|end"
        android:text="[=10=] / [=10=]"
        android:maxLines="1"
        android:textColor="@color/black"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <android.support.constraint.ConstraintLayout
        android:id="@+id/progress_bar"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        app:layout_constraintStart_toStartOf="parent" 
        android:background="#004090">
        <TextView
            android:id="@+id/left_front_textview"
            android:layout_width="180dp"
            android:layout_height="wrap_content"
            android:text="Entertainment"
            android:singleLine="true"
            android:textColor="#fff"
            android:ellipsize="none"
            android:layout_paddingStart="12dp"
            android:layout_paddingLeft="12dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>  
        <TextView
            android:id="@+id/right_bottom_amount_textview"
            android:layout_width="180dp"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:gravity="center_vertical|end"
            android:text="[=10=] / [=10=]"
            android:layout_alignRight="@id/left_front_textview"
            android:textColor="#ffffff"
            android:layout_paddingEnd="12dp"
            android:layout_paddingRight="12dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@id/left_front_textview"/>
    </android.support.constraint.ConstraintLayout>  

</android.support.constraint.ConstraintLayout>

所以基本上我们会有:

父布局(parentview):具有固定的layout_width360dp并包含初始的Grey TextViews

Progress 布局(progress_bar): 也有固定大小360dp 并包含前面White TextViews

因此我们将 Progress layout (progress_bar) 叠加在其父布局之上,并增加或减少 layout_width 以模拟不闪烁的进度:

下图显示了静态 layout_width 为 74dp 的进度布局;另请注意,根据上面提供的示例,progress layout_width 的范围可以是 1dp to max:360dp1% to 100% of parentview width.