2014-10-27 2 views
6

Я ищу плавный способ реализовать «состояние» в Android, как показано в трех примерах ниже. Поскольку я не поклонник изобретать колесо, я хотел бы спросить, есть ли какая-нибудь библиотека, о которой я не знаю.State progressbar android

Я искал его и не мог найти lib, поэтому, я думаю, мне нужно реализовать его самостоятельно. Что было бы самым простым решением? Должен ли я расширять ProgressBar, или я должен делать это с нуля? Есть ли у вас какие-либо предложения или учебные пособия, которые я мог бы создать?

Desired Progressbar

enter image description here

enter image description here

+0

Смотрите здесь: http://escrow.aliexpress.com //stackoverflow.com/questions/14472144/how-to -make-сегментированный-SeekBar-слайдер вид -как следования. Это поисковый инструмент, но вы можете легко отключить пользователей от изменения значения поиска. Вам также придется изменить стиль, но базовая библиотека с открытым исходным кодом и гибкой: https://github.com/karabaralex/android-comboseekbar – kha

ответ

12

Update

Пожалуйста, смотрите this sample project, также GIF прилагается дать обзор.

GIF Picture

Вы можете настроить следующие вашему требованию.

Progress

import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.RectF; 
import android.os.Bundle; 
import android.os.Parcelable; 
import android.util.AttributeSet; 
import android.view.View; 

public class NumberProgressBar extends View { 

    private Context mContext; 

    /** 
    * The max progress, default is 100 
    */ 
    private int mMax = 100; 

    /** 
    * current progress, can not exceed the max progress. 
    */ 
    private int mProgress = 0; 

    /** 
    * the progress area bar color 
    */ 
    private int mReachedBarColor; 

    /** 
    * the bar unreached area color. 
    */ 
    private int mUnreachedBarColor; 

    /** 
    * the progress text color. 
    */ 
    private int mTextColor; 

    /** 
    * the progress text size 
    */ 
    private float mTextSize; 

    /** 
    * the height of the reached area 
    */ 
    private float mReachedBarHeight; 

    /** 
    * the height of the unreached area 
    */ 
    private float mUnreachedBarHeight; 

    /** 
    * the suffix of the number. 
    */ 
    private String mSuffix = "%"; 

    /** 
    * the prefix. 
    */ 
    private String mPrefix = ""; 


    private final int default_text_color = Color.rgb(66, 145, 241); 
    private final int default_reached_color = Color.rgb(66,145,241); 
    private final int default_unreached_color = Color.rgb(204, 204, 204); 
    private final float default_progress_text_offset; 
    private final float default_text_size; 
    private final float default_reached_bar_height; 
    private final float default_unreached_bar_height; 

    /** 
    * for save and restore instance of progressbar. 
    */ 
    private static final String INSTANCE_STATE = "saved_instance"; 
    private static final String INSTANCE_TEXT_COLOR = "text_color"; 
    private static final String INSTANCE_TEXT_SIZE = "text_size"; 
    private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height"; 
    private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color"; 
    private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height"; 
    private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color"; 
    private static final String INSTANCE_MAX = "max"; 
    private static final String INSTANCE_PROGRESS = "progress"; 
    private static final String INSTANCE_SUFFIX = "suffix"; 
    private static final String INSTANCE_PREFIX = "prefix"; 
    private static final String INSTANCE_TEXT_VISBILITY = "text_visibility"; 

    private static final int PROGRESS_TEXT_VISIBLE = 0; 
    private static final int PROGRESS_TEXT_INVISIBLE = 1; 



    /** 
    * the width of the text that to be drawn 
    */ 
    private float mDrawTextWidth; 

    /** 
    * the drawn text start 
    */ 
    private float mDrawTextStart; 

    /** 
    *the drawn text end 
    */ 
    private float mDrawTextEnd; 

    /** 
    * the text that to be drawn in onDraw() 
    */ 
    private String mCurrentDrawText; 

    /** 
    * the Paint of the reached area. 
    */ 
    private Paint mReachedBarPaint; 
    /** 
    * the Painter of the unreached area. 
    */ 
    private Paint mUnreachedBarPaint; 
    /** 
    * the Painter of the progress text. 
    */ 
    private Paint mTextPaint; 

    /** 
    * Unreached Bar area to draw rect. 
    */ 
    private RectF mUnreachedRectF = new RectF(0,0,0,0); 
    /** 
    * reached bar area rect. 
    */ 
    private RectF mReachedRectF = new RectF(0,0,0,0); 

    /** 
    * the progress text offset. 
    */ 
    private float mOffset; 

    /** 
    * determine if need to draw unreached area 
    */ 
    private boolean mDrawUnreachedBar = true; 

    private boolean mDrawReachedBar = true; 

    private boolean mIfDrawText = true; 

    public enum ProgressTextVisibility{ 
     Visible,Invisible 
    }; 



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

    public NumberProgressBar(Context context, AttributeSet attrs) { 
     this(context, attrs, R.attr.numberProgressBarStyle); 
    } 

    public NumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 

     mContext = context; 

     default_reached_bar_height = dp2px(1.5f); 
     default_unreached_bar_height = dp2px(1.0f); 
     default_text_size = sp2px(10); 
     default_progress_text_offset = dp2px(3.0f); 

     //load styled attributes. 
     final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NumberProgressBar, 
       defStyleAttr, 0); 

     mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color); 
     mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color,default_unreached_color); 
     mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color,default_text_color); 
     mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size); 

     mReachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_reached_bar_height,default_reached_bar_height); 
     mUnreachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_unreached_bar_height,default_unreached_bar_height); 
     mOffset = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_offset,default_progress_text_offset); 

     int textVisible = attributes.getInt(R.styleable.NumberProgressBar_progress_text_visibility,PROGRESS_TEXT_VISIBLE); 
     if(textVisible != PROGRESS_TEXT_VISIBLE){ 
      mIfDrawText = false; 
     } 

     setProgress(attributes.getInt(R.styleable.NumberProgressBar_progress,0)); 
     setMax(attributes.getInt(R.styleable.NumberProgressBar_max, 100)); 
     // 
     attributes.recycle(); 

     initializePainters(); 

    } 

    @Override 
    protected int getSuggestedMinimumWidth() { 
     return (int)mTextSize; 
    } 

    @Override 
    protected int getSuggestedMinimumHeight() { 
     return Math.max((int)mTextSize,Math.max((int)mReachedBarHeight,(int)mUnreachedBarHeight)); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     setMeasuredDimension(measure(widthMeasureSpec,true), measure(heightMeasureSpec,false)); 
    } 

    private int measure(int measureSpec,boolean isWidth){ 
     int result; 
     int mode = MeasureSpec.getMode(measureSpec); 
     int size = MeasureSpec.getSize(measureSpec); 
     int padding = isWidth?getPaddingLeft()+getPaddingRight():getPaddingTop()+getPaddingBottom(); 
     if(mode == MeasureSpec.EXACTLY){ 
      result = size; 
     }else{ 
      result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight(); 
      result += padding; 
      if(mode == MeasureSpec.AT_MOST){ 
       if(isWidth) { 
        result = Math.max(result, size); 
       } 
       else{ 
        result = Math.min(result, size); 
       } 
      } 
     } 
     return result; 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     if(mIfDrawText){ 
      calculateDrawRectF(); 
     }else{ 
      calculateDrawRectFWithoutProgressText(); 
     } 

     if(mDrawReachedBar){ 
      canvas.drawRect(mReachedRectF,mReachedBarPaint); 
     } 

     if(mDrawUnreachedBar) { 
      canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint); 
     } 

     if(mIfDrawText) 
      canvas.drawText(mCurrentDrawText,mDrawTextStart,mDrawTextEnd,mTextPaint); 
    } 

    private void initializePainters(){ 
     mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     mReachedBarPaint.setColor(mReachedBarColor); 

     mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     mUnreachedBarPaint.setColor(mUnreachedBarColor); 

     mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     mTextPaint.setColor(mTextColor); 
     mTextPaint.setTextSize(mTextSize); 
    } 


    private void calculateDrawRectFWithoutProgressText(){ 
     mReachedRectF.left = getPaddingLeft(); 
     mReachedRectF.top = getHeight()/2.0f - mReachedBarHeight/2.0f; 
     mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight())/(getMax()*1.0f) * getProgress() + getPaddingLeft(); 
     mReachedRectF.bottom = getHeight()/2.0f + mReachedBarHeight/2.0f; 

     mUnreachedRectF.left = mReachedRectF.right; 
     mUnreachedRectF.right = getWidth() - getPaddingRight(); 
     mUnreachedRectF.top = getHeight()/2.0f + - mUnreachedBarHeight/2.0f; 
     mUnreachedRectF.bottom = getHeight()/2.0f + mUnreachedBarHeight/2.0f; 
    } 

    private void calculateDrawRectF(){ 

     mCurrentDrawText = String.format("%d" ,getProgress()*100/getMax()); 
     mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix; 
     mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText); 

     if(getProgress() == 0){ 
      mDrawReachedBar = false; 
      mDrawTextStart = getPaddingLeft(); 
     }else{ 
      mDrawReachedBar = true; 
      mReachedRectF.left = getPaddingLeft(); 
      mReachedRectF.top = getHeight()/2.0f - mReachedBarHeight/2.0f; 
      mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight())/(getMax()*1.0f) * getProgress() - mOffset + getPaddingLeft(); 
      mReachedRectF.bottom = getHeight()/2.0f + mReachedBarHeight/2.0f; 
      mDrawTextStart = (mReachedRectF.right + mOffset); 
     } 

     mDrawTextEnd = (int) ((getHeight()/2.0f) - ((mTextPaint.descent() + mTextPaint.ascent())/2.0f)) ; 

     if((mDrawTextStart + mDrawTextWidth)>= getWidth() - getPaddingRight()){ 
      mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth; 
      mReachedRectF.right = mDrawTextStart - mOffset; 
     } 

     float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset; 
     if(unreachedBarStart >= getWidth() - getPaddingRight()){ 
      mDrawUnreachedBar = false; 
     }else{ 
      mDrawUnreachedBar = true; 
      mUnreachedRectF.left = unreachedBarStart; 
      mUnreachedRectF.right = getWidth() - getPaddingRight(); 
      mUnreachedRectF.top = getHeight()/2.0f + - mUnreachedBarHeight/2.0f; 
      mUnreachedRectF.bottom = getHeight()/2.0f + mUnreachedBarHeight/2.0f; 
     } 
    } 
    /** 
    * get progress text color 
    * @return progress text color 
    */ 
    public int getTextColor() { 
     return mTextColor; 
    } 

    /** 
    * get progress text size 
    * @return progress text size 
    */ 
    public float getProgressTextSize() { 
     return mTextSize; 
    } 

    public int getUnreachedBarColor() { 
     return mUnreachedBarColor; 
    } 

    public int getReachedBarColor() { 
     return mReachedBarColor; 
    } 

    public int getProgress() { 
     return mProgress; 
    } 

    public int getMax() { 
     return mMax; 
    } 

    public float getReachedBarHeight(){ 
     return mReachedBarHeight; 
    } 

    public float getUnreachedBarHeight(){ 
     return mUnreachedBarHeight; 
    } 

    public void setProgressTextSize(float TextSize) { 
     this.mTextSize = TextSize; 
     mTextPaint.setTextSize(mTextSize); 
     invalidate(); 
    } 

    public void setProgressTextColor(int TextColor) { 
     this.mTextColor = TextColor; 
     mTextPaint.setColor(mTextColor); 
     invalidate(); 
    } 

    public void setUnreachedBarColor(int BarColor) { 
     this.mUnreachedBarColor = BarColor; 
     mUnreachedBarPaint.setColor(mReachedBarColor); 
     invalidate(); 
    } 

    public void setReachedBarColor(int ProgressColor) { 
     this.mReachedBarColor = ProgressColor; 
     mReachedBarPaint.setColor(mReachedBarColor); 
     invalidate(); 
    } 

    public void setReachedBarHeight(float height){ 
     mReachedBarHeight = height; 
    } 

    public void setUnreachedBarHeight(float height){ 
     mUnreachedBarHeight = height; 
    } 

    public void setMax(int Max) { 
     if(Max > 0){ 
      this.mMax = Max; 
      invalidate(); 
     } 
    } 

    public void setSuffix(String suffix){ 
     if(suffix == null){ 
      mSuffix = ""; 
     }else{ 
      mSuffix = suffix; 
     } 
    } 

    public String getSuffix(){ 
     return mSuffix; 
    } 

    public void setPrefix(String prefix){ 
     if(prefix == null) 
      mPrefix = ""; 
     else{ 
      mPrefix = prefix; 
     } 
    } 

    public String getPrefix(){ 
     return mPrefix; 
    } 

    public void incrementProgressBy(int by){ 
     if(by > 0){ 
      setProgress(getProgress() + by); 
     } 
    } 

    public void setProgress(int Progress) { 
     if(Progress <= getMax() && Progress >= 0){ 
      this.mProgress = Progress; 
      invalidate(); 
     } 
    } 

    @Override 
    protected Parcelable onSaveInstanceState() { 
     final Bundle bundle = new Bundle(); 
     bundle.putParcelable(INSTANCE_STATE,super.onSaveInstanceState()); 
     bundle.putInt(INSTANCE_TEXT_COLOR,getTextColor()); 
     bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize()); 
     bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT,getReachedBarHeight()); 
     bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT,getUnreachedBarHeight()); 
     bundle.putInt(INSTANCE_REACHED_BAR_COLOR,getReachedBarColor()); 
     bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR,getUnreachedBarColor()); 
     bundle.putInt(INSTANCE_MAX,getMax()); 
     bundle.putInt(INSTANCE_PROGRESS,getProgress()); 
     bundle.putString(INSTANCE_SUFFIX,getSuffix()); 
     bundle.putString(INSTANCE_PREFIX,getPrefix()); 
     bundle.putBoolean(INSTANCE_TEXT_VISBILITY, getProgressTextVisibility()); 
     return bundle; 
    } 

    @Override 
    protected void onRestoreInstanceState(Parcelable state) { 
     if(state instanceof Bundle){ 
      final Bundle bundle = (Bundle)state; 
      mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR); 
      mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE); 
      mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT); 
      mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT); 
      mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR); 
      mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR); 
      initializePainters(); 
      setMax(bundle.getInt(INSTANCE_MAX)); 
      setProgress(bundle.getInt(INSTANCE_PROGRESS)); 
      setPrefix(bundle.getString(INSTANCE_PREFIX)); 
      setSuffix(bundle.getString(INSTANCE_SUFFIX)); 
      setProgressTextVisibility(bundle.getBoolean(INSTANCE_TEXT_VISBILITY) ? ProgressTextVisibility.Visible : ProgressTextVisibility.Invisible); 
      super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE)); 
      return; 
     } 
     super.onRestoreInstanceState(state); 
    } 

    public float dp2px(float dp) { 
     final float scale = getResources().getDisplayMetrics().density; 
     return dp * scale + 0.5f; 
    } 

    public float sp2px(float sp){ 
     final float scale = getResources().getDisplayMetrics().scaledDensity; 
     return sp * scale; 
    } 

    public void setProgressTextVisibility(ProgressTextVisibility visibility){ 
     mIfDrawText = visibility == ProgressTextVisibility.Visible; 
     invalidate(); 
    } 

    public boolean getProgressTextVisibility() { 
     return mIfDrawText; 
    } 

} 

Link 1

Link 2

Link 3

Link 4

Link 5

Link 6

Вы также можете сделать это с линейной планировкой. Я сделал простой пример, просто простой пример.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <LinearLayout 
     android:id="@+id/ll_progress" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerHorizontal="true" 
     android:background="@drawable/layout" > 

     <ImageView 
      android:id="@+id/ImageView01" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="10dp" 
      android:layout_marginTop="14dp" 
      android:src="@drawable/bg_1" /> 

     <ImageView 
      android:id="@+id/imageView1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="38dp" 
      android:layout_marginTop="14dp" 
      android:src="@drawable/bg_1" /> 


     <ImageView 
      android:id="@+id/imageView12" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="35dp" 
      android:layout_marginTop="14dp" 
      android:src="@drawable/bg_1" /> 

    </LinearLayout> 

</RelativeLayout> 

bg_1 bg layout

MainActivity.java

import java.util.concurrent.TimeUnit; 

import android.app.Activity; 
import android.graphics.BitmapFactory; 
import android.graphics.drawable.BitmapDrawable; 
import android.graphics.drawable.Drawable; 
import android.graphics.drawable.TransitionDrawable; 
import android.os.Bundle; 
import android.os.Handler; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 

public class MainActivity extends Activity { 

    LinearLayout llProgress; 
    Handler handler; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     llProgress = (LinearLayout) findViewById(R.id.ll_progress); 
     handler = new Handler(getMainLooper()); 

     startTransition(); 
    } 

    int prevChild = 0; 

    private void startTransition() { 
     // create the transition layers 
     Drawable[] layers = new Drawable[2]; 
     layers[0] = new BitmapDrawable(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.bg)); 
     layers[1] = new BitmapDrawable(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.bg_1)); 

     final TransitionDrawable[] transitionDrawable = new TransitionDrawable[llProgress.getChildCount()]; 
     for (int i = 0; i < llProgress.getChildCount(); i++) { 
      transitionDrawable[i] = new TransitionDrawable(layers); 
      ((ImageView) llProgress.getChildAt(i)).setImageDrawable(transitionDrawable[i]); 
     } 

     handler.postDelayed(new Runnable() { 

      @Override 
      public void run() { 
       transitionDrawable[prevChild++].startTransition(1000); 
       if(prevChild > llProgress.getChildCount() - 1){ 
        prevChild = 0; 
       } 
       handler.postDelayed(this, 1000 * 3); 
      } 
     }, 1000 * 3); 

    } 

1 2

-1

В ProgressBar виджет делегирует рисунок это прогресс в этом Присвоенный прогресс Drawable путем установки соответствующего уровня на нем. Значение по умолчанию * progress Drawable является layer-list**, который содержит три слоя: фон, прогресс и средний прогресс. Последние два завернуты в контейнеры clip или scale, которые автоматически обрезаются или масштабируются до их процента в зависимости от их уровней. Им также назначаются специальные идентификаторы, которые ProgressBar ищет и обрабатывает конкретно вместо всего Drawable, если Drawable является layer-list.

В вашем случае, поскольку приращения прогресса не все равны, вы можете использовать контейнер для рисования level-list в качестве вашего уровня прогресса и предоставить вам активы для всех ваших приращений прогресса. В качестве альтернативы, если вы хотите сделать ее динамичной, вы можете создать подклассу Drawable с соответствующей логикой рисования на основе ее уровня.

Вот пример XML для ресурса прогресса Drawable использования level-list:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:id="@android:id/background" 
      android:drawable="@drawable/progress_bg" /> 
    <item android:id="@android:id/progress"> 
     <level-list> 
      <item android:drawable="@android:color/transparent" /> 
      <item android:drawable="@drawable/progress_1" /> 
      <item android:drawable="@drawable/progress_2" /> 
      <item android:drawable="@drawable/progress_3" /> 
     </level-list> 
    </item> 
</layer-list> 


* Вы можете найти оригинальную, не Хола версию here и версию Хола here и here.
** Вы можете найти список стандартных фреймов Drawable s, которые могут быть определены в XML here.