Heaven
Heaven

Reputation: 536

Android implement a progressBar with two clip textview on it

I am going to implement a progress bar with two clip textview on it. Something like: progressbar_1 progressbar_2 progressbar_3

I use some trick (using paddingEnd/paddingStart, back/front textview to achieve the clip effect for textview) to implement it:

    // 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);
                }
            }
        });

    }

And the layout is:

<?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="$0 / $0"
        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="$0 / $0"
        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>

When I run this code, it almost achieved the effect I want. But it has one issue. Textview keeps flashing while doing animation, and when animation finished, the color of textview sometime turn all white. result_1 result_2

I think there may be something wrong in leftFrontText.post() of setLeftFrontTextViewPadding, like how I get width of textview. But I can't be quite sure. Can anyone show me the right way to do this? Or any other better way to implement this kind of progress bar.

Upvotes: 4

Views: 367

Answers (1)

Giddy Naya
Giddy Naya

Reputation: 4658

Why not try this approach and leverage the power of ConstraintLayout as your progressBar:

<?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="$0 / $0"
        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="$0 / $0"
            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>

So basically we would have:

The Parent layout (parentview): having a fixed layout_width 360dp and contains the initial Grey TextViews

enter image description here

The Progress layout (progress_bar): also having a fixed size 360dp and contains the front White TextViews

enter image description here

Hence we overlay the Progress layout (progress_bar) ontop of its parent layout and increase or decrease the layout_width to simulate a progress without flickering:

The image below shows the progress layout having a static layout_width of 74dp; Also note that progress layout_width based on the example provided above can range from 1dp to max:360dp or otherwise 1% to 100% of parentview width.

enter image description here

Upvotes: 1

Related Questions