Как залить фон button частично?

600

Привет! Нужно вводить число от 0 до 1 в edittext, а после заливать цветом часть фона button в соответствии с введенным числом( т.е. ввели 0.25 - заливаем четверть кнопки)

В списке аттрибутов ничего подобного, к сожалению, нет

2 ответа

600

Предлагаю свой вариант решения вопроса - создание кастомной кнопки с необходимой функцией. Сразу ссылка GitHub на небольшой сэмпл, как это все работает и картинка :

Реализация проста и состоит из менее десятка строчек - подрисовывать на кнопку дополнительный слой с шириной, которую мы можем установить сами:

"Мучить" будем очень модную сейчас material-кнопку (AppCompatButton) из последней support.v7 - 22.1 , но то же самое можно проделать с любым виджетом, это не принципиально. Собственно сам класс кастомной кнопки ProgressButton.java:

public class ProgressButton extends AppCompatButton {
 private float mRatio;
 private int mColor = Color.GREEN;

 public ProgressButton(Context context) {
    super(context);
    init();
 }

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

 public ProgressButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
 }

 void init(){

 }

 public void setRatio (float ratio){
    mRatio = ratio;
    invalidate();
 }

 public void setColor (int color){
    mColor = color;
    invalidate();
 }

 @Override
 protected void onDraw(Canvas canvas) {

    Drawable fill = getResources().getDrawable(R.drawable.abc_btn_default_mtrl_shape);
    fill.setColorFilter( mColor, PorterDuff.Mode.MULTIPLY);
    fill.setAlpha(128);
    fill.setBounds(0, 0, (int) (getWidth()*mRatio),  getHeight());
    fill.draw(canvas);
    super.onDraw(canvas);
  }
}

в качестве дополнительного слоя мы используем тот же xml (abc_btn_default_mtrl_shape.xml), что используется и для прорисовки бэкграунда самой кнопки, окрашивая его в собственный цвет, но можно использовать и любой собственный вид при необходимости. Прозрачность устанавливается для того, чтобы эффект нажатия был виден по всей кнопке, а не только на не окрашенной части.

кастомная кнопка реализует методы:

  1. setRatio(float ratio) - установить процент заполнения фона кнопки - число от 0 до 1.
  2. setColor(Color color) - установить цвет заливки

Теперь, как это все работает. Простой пример заполняет часть кнопки при нажатии на нее:

public class MainActivity extends AppCompatActivity {

 ProgressButton button;
 float ratio;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button = (ProgressButton) findViewById(R.id.progress_button);

 }

 public void onClicked (View view) {

   button.setRatio(ratio);
   ratio = ratio +0.3f;
   if (ratio >= 1) ratio = 0;
 }
}

activity_main.xml


600

Можно использовать ScaleDrawable.

res/drawable/progress_indicator_shape.xml - drawable, размеры которого мы будем изменять. Просто зелёный прямоугольник:

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

res/drawable/progress_indicator.xml - ScaleDrawable

layout (основная часть):

<edittext android:id="@+id/value" android:layout_width="100dp" android:layout_height="wrap_content" android:inputtype="numberDecimal">

    <framelayout android:id="@+id/button_frame" android:background="@drawable/progress_indicator" android:layout_marginleft="4dp" android:layout_width="wrap_content" android:layout_height="wrap_content">

        <button android:id="@+id/button" android:background="?android:selectableItemBackground" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button">
    
</button></framelayout></edittext>

В разметке кнопка завернута в FrameLayout и сделана прозрачной с бэкраундом selectableItemBackground, чтобы сохранить ей обратную связь на нажатие. Можно завернуть два бэкраунда в один LayerListDrawable.

Код:

View mButtonFrameView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(...);
    final EditText valueView = (EditText)findViewById(R.id.value);
    mButtonFrameView = findViewById(R.id.button_frame);
    View buttonView = findViewById(R.id.button);
    buttonView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            float progress = 0;
            try {
                progress = Float.valueOf(valueView.getText().toString());
                if (progress < 0) progress = 0;
                if (progress > 1) progress = 1;
            } catch (NumberFormatException ignore) {}
            updateButtonProgress(progress);
        }
    });
    updateButtonProgress(0);
}

void updateButtonProgress(float progress) {
    Drawable background = mButtonFrameView.getBackground(); // ScaleDrawable
    background.setLevel((int)(10000f * progress));
}

licensed under cc by-sa 3.0 with attribution.