2010-10-01 13 views
7

Estoy tratando de hacer algo similar a this pero en Android.Widget de ProgressBar personalizado

alt text

En Android puedo extender el ProgressBar pero estoy dudando de cómo añadir el TextViews en la parte superior. En iphone fue fácil porque puedo usar posiciones absolutas, pero no aquí.

¿Alguna idea?

EDIT: Decidí usar SeekBar en lugar de ProgressBar para agregar el pulgar dibujable. Comenté a continuación. Algunos puntos para notar:

  • Estoy usando valores codificados, en realidad tres pero puede ser más o menos.
  • Cuando se mueve el pulgar se mueve a 50, pero se debe mover a las diferentes opciones.
  • Estoy usando píxeles en lugar de ppp. Debería arreglar eso.
  • Necesito resolver la falta de animación cuando el pulgar se mueve.

Mi progreso hasta ahora:

public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener { 
    private SeekBar mSlider; 
    private Context mContext; 
    private int mSize = 3; 
    private TextView[] mTextViews; 
    private String[] mTexts = {"Nafta", "Gas", "Gasoil"}; 

    public SliderFrameLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     mContext = context; 
     setWillNotDraw(false); 
     mTextViews = new TextView[mSize]; 
     addSlider(); 
     addTextViews(); 
    } 

    private void addTextViews() { 
     for (int i=0 ; i < mSize ; i++) { 
      TextView tv; 
      tv = new TextView(mContext); 
      tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 
        LayoutParams.WRAP_CONTENT)); 
      tv.setText(mTexts[i]); 
      mTextViews[i] = tv; 
      addView(tv);  
     } 
    } 

    private void addSlider() { 
     FrameLayout fl = new FrameLayout(mContext, null); 
     LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 
     fl.setLayoutParams(params); 
     fl.setPadding(30, 30, 30, 0); 


     mSlider = new SeekBar(mContext, null); 
     LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 
     //lp.setMargins(30, 30, 30, 0); 
     //mSlider.setPadding(30, 30, 30, 0); 
     mSlider.setLayoutParams(lp); 
     //mSlider.setMax(mSize-1); 
     mSlider.setThumbOffset(30); 
     //mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track)); 
     //mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb)); 
     mSlider.setOnSeekBarChangeListener(this); 
     //addView(mSlider); 

     fl.addView(mSlider); 
     addView(fl); 

    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 


     Rect rectf = new Rect(); 
     mSlider.getLocalVisibleRect(rectf); 

    Log.d("WIDTH  :",String.valueOf(rectf.width())); 
    Log.d("HEIGHT  :",String.valueOf(rectf.height())); 
    Log.d("left   :",String.valueOf(rectf.left)); 
    Log.d("right  :",String.valueOf(rectf.right)); 
    Log.d("top   :",String.valueOf(rectf.top)); 
    Log.d("bottom  :",String.valueOf(rectf.bottom)); 

     int sliderWidth = mSlider.getWidth(); 

     int padding = sliderWidth/(mSize-1); 

     for (int i=0 ; i < mSize ; i++) { 
      TextView tv = mTextViews[i]; 
      tv.setPadding(i* padding, 0, 0, 0); 
     } 
    } 

    @Override 
    public void onProgressChanged(SeekBar seekBar, int progress, 
      boolean fromUser) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onStartTrackingTouch(SeekBar seekBar) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onStopTrackingTouch(SeekBar seekBar) { 
     Log.d("SEEK", "value: " + seekBar.getProgress()); 
     seekBar.setProgress(50); 
    } 
} 
+0

¿ha creado exactamente el mismo progreso que uno en iphone? –

+0

@NewToiOS: sip. Hace mucho tiempo :) – Macarse

Respuesta

8

Ya está redefiniendo onDraw, ¿por qué no simplemente dibuja las cadenas de texto usted mismo? En lugar de pasar por encima de agregar TextViews y jugar con el relleno, simplemente use canvas.drawText para dibujar físicamente las cadenas de texto en el lugar correcto.

Se puede especificar el estilo y color del texto utilizando un objeto Paint:

Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
textPaint.setColor(r.getColor(R.color.text_color)); 
textPaint.setFakeBoldText(true); 
textPaint.setSubpixelText(true); 
textPaint.setTextAlign(Align.LEFT); 

y conseguir el posicionamiento exacto mediante el método measureText en ese objeto pintura para encontrar lo ancho de una cadena en particular sería cuando dibujado en un lienzo:

textWidth = (int)textPaint.measureText(mTexts[i]); 

a continuación, puede iterar sobre el conjunto de cadenas de texto y dibujar cada cadena en el lugar correcto.

@Override 
protected void onDraw(Canvas canvas) { 
    int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING; 
    int separation = myWidth/(mSize-1); 

    for (int i = 0; i++; i < mSize) { 
    int textWidth = (int)textPaint.measureText(mTexts[i]); 
    canvas.drawText(mTexts[i], 
        LEFT_PADDING+(i*separation)-(int)(textWidth/2), 
        TOP_PADDING, 
        textPaint); 
    } 
} 

Usted probablemente querrá hacer las mediciones en lugar de onMeasure onDraw, y se debe, probablemente, sólo medir el ancho de cada cuerda cuando se cambia el texto o la pintura, pero lo he puesto todo en un lugar para (con suerte) hacerlo más fácil de seguir.

+0

Genial, lo usaré para el texto. Lo único que me falta es cómo animar el pulgar al moverlo En iPhone tuve algo como 'moveToPosition (int position, boolean animate)' pero no hay nada similar en Android. ¿Alguna idea sobre eso? – Macarse

+0

No hay una manera simple de lograr lo que describes (y tu código es la implementación de onStopTrackingTouch redundante: el valor de avance de Seekbar ya se habrá establecido correctamente con el toque que se está rastreando). Supongo que desea animar la ubicación del pulgar en el cas e donde el usuario hace clic a la izquierda o derecha de la posición actual? Debería anular el controlador onTouch, escuchar ACTION_UP e implementar un bucle que cambie la posición del control deslizante en un intervalo adecuado para simular la animación. –

0

Puede utilizar this ... no ser correcta lo que busca ... pero muy fácil de configurar y personalizar ...

+0

Thorat: En Android no en el iphone. – Macarse

+0

HHmmm .... lo siento – kthorat

1

Justo un intento. Puede poner su barra de progreso personalizada dentro de un FrameLayout y luego, dentro de este diseño, debe agregar tres TextViews con fill_parent como ancho. Luego puede alinear los tres textos de esta manera: izquierda, centro y derecha. Sus textos no deben sobrescribirse y puede ajustar un poco su posición usando márgenes.

+0

El número de 'TextViews' no es fijo. La imagen tiene 3, pero puede tener 2, 4, 5, 6, etc. – Macarse

+0

Ok. De modo que puede usar wrap_content en lugar de fill_parent para las textviews y distribuirlas en el espacio disponible utilizando márgenes. Sé que no es una solución perfecta, pero de lo contrario debe sobrescribir el método de dibujo de la vista y hacerlo usted mismo. – MaxFish

+0

Editaré mi respuesta con lo que tengo hasta ahora. – Macarse

0

Puede configurar los TextViews tener:

android:layout_width="0dp" 
android:layout_weight="1" 

Esto permitirá que el marco androide hacerse cargo de la colocación de los TextViews y lo libera de calcular manualmente el relleno de cada uno.

+0

Solo puedo usar eso dentro de un 'LinearLayout' :( – Macarse

+0

He podido usar esto para EditTexts, TextViews y otros widgets al especificar el diseño en XML. Sin embargo, no estoy seguro de hacerlo programáticamente como está aquí. – danh32

+0

¿Por qué no simplemente agregar un 'LinearLayout' a su' FrameLayout' para contener su 'TextViews' para que pueda usar la ponderación? – jqpubliq