2013-03-29

Ein SeekBar-Beispiel

Mit SeekBars kann man in Android bequem Werte einstellen. Der folgende Screenshot zeigt die Regulierung der Display-Helligkeit.
Screenshot: Display-Helligkeit einstellen
Display-Helligkeit einstellen
Das Hin und Her schieben des kreisrunden Knopfes ist fingerfreundlich. Allerdings fehlt meiner Meinung nach eine Rückmeldung, wie stark sich der Wert schon geändert hat. Natürlich lässt sich so etwas leicht nachrüsten. Die folgenden Quelltextfragmente sind einer zukünftigen Version von TKWeek entnommen. Dort setze ich die SeekBar unter anderem ein, um die Deckkraft meiner Widget-Hintergründe zu steuern.
Screenshot: SeekBar in TKWeek
SeekBar in TKWeek
Lassen Sie uns zunächst einen Blick auf die Layoutdatei werfen. Sie besteht aus zwei geschachtelten LinearLayouts. Das äußere ordnet zwei Zeilen vertikal an, nämlich die Beschriftung Opacity sowie die SeekBar mit der Angabe 0 / 255. Das innere LinearLayout positioniert diese beiden Elemente nebeneinander, also in horizontaler Richtung.
 <?xml version="1.0" encoding="utf-8"?>  
 <!--  
   widget_preference.xml  
   TKWeek (c) Thomas Künneth 2013  
   Alle Rechte beim Autoren. All rights reserved.  
 -->  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="match_parent"  
   android:layout_height="wrap_content"  
   android:orientation="vertical"  
   android:padding="6dp"  
 >  
   <TextView   
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="@string/widget_opacity"  
   />  
   <LinearLayout  
     android:layout_width="match_parent"  
     android:layout_height="wrap_content"  
     android:orientation="horizontal"  
   >  
     <SeekBar  
       android:id="@+id/widget_opacity"  
       android:layout_width="0dp"  
       android:layout_height="wrap_content"  
       android:layout_weight="1"  
     />  
     <TextView   
       android:id="@+id/widget_opacity_info"  
       android:layout_width="wrap_content"  
       android:layout_height="match_parent"  
       android:gravity="center_vertical|right"  
       android:ems="5"  
     />  
   </LinearLayout>  
 </LinearLayout>  
Geschachtelte LinearLayouts werden gelegentlich kritisiert, weil sie etwas mehr Speicherplatz als optimierte RelativeLayouts verbrauchen. Allerdings sind sie leicht les- und wartbar. Sobald der Beispiel-Dialog weitere Elemente (denken Sie an Picker zum Auswählen von Vorder- und Hintergrundfarbe) enthält, wird es unübersichtlich. Ich würde deshalb davon abraten, mehrzeilige Label-Element-Konstruktionen mit einem einzigen RelativeLayout zu realisieren.
Ist Ihnen aufgefallen, dass die TextView rechts neben der SeekBar die merkwürdige Zuweisung android:ems="5" enthält? Damit sorgen wir für eine feste, Zeichensatz-abhängige Breite und verhindern in Verbindung mit der rechtsbündigen Ausrichtung des Texts ein “Zappeln” der SeekBar-Breite, wenn sich die Textlänge ändert. 1 / 255 braucht weniger Platz als beispielsweise 255 / 255.
Die x / y-Ausgabe wird in strings.xml definiert:
 <!-- aus strings.xml -->  
 <string name="int_slash_int">%1$d / %2$d</string>  
Das folgende Quelltextfragment zeigt, wie die Klasse SeekBar verwendet wird. Es entfaltet die bereits vorgestellte Layoutdatei und bettet sie in einen Dialog ein.
-->
/*
 * WidgetPreference.java
 *
 * TKWeek (c) Thomas Künneth 2013
 * Alle Rechte beim Autoren. All rights reserved.
 */
package com.thomaskuenneth.android.util;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.thomaskuenneth.tkweek.DateWidget;
import com.thomaskuenneth.tkweek.DayOfYearWidget;
import com.thomaskuenneth.tkweek.R;
import com.thomaskuenneth.tkweek.TKWeek;

/**
 * Stellt einen Dialog dar, in dem die Deckkraft des Widget-Hintergrunds
 * eingestellt werden kann. Der Wert wird in den SharedPreferences abgelegt.
 *
 * @author Thomas Künneth
 */
public class WidgetPreference extends DialogPreference implements
    OnSeekBarChangeListener {

  private static final String TAG = WidgetPreference.class.getSimpleName();
  private static final String OPACITY = "opacity";

  private TextView seekbarInfo;
  private SeekBar seekbar;

  public WidgetPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
    setDialogLayoutResource(R.layout.widget_preference);
  }

  public static int getOpacity(Context c) {
    SharedPreferences prefs = c.getSharedPreferences(TAG,
        Context.MODE_PRIVATE);
    return prefs.getInt(OPACITY, 128);
  }

  @Override
  protected void onBindDialogView(View view) {
    super.onBindDialogView(view);
    seekbarInfo = (TextView) view.findViewById(R.id.widget_opacity_info);
    seekbar = (SeekBar) view.findViewById(R.id.widget_opacity);
    seekbar.setOnSeekBarChangeListener(this);
    seekbar.setMax(255);
    seekbar.setProgress(getOpacity(getContext()));
  }

  @Override
  protected void onDialogClosed(boolean positiveResult) {
    if (positiveResult) {
      SharedPreferences prefs = getContext().getSharedPreferences(TAG,
          Context.MODE_PRIVATE);
      Editor e = prefs.edit();
      e.putInt(OPACITY, seekbar.getProgress());
      e.commit();
      TKWeek.updateWidgets(getContext(), DateWidget.class);
      TKWeek.updateWidgets(getContext(), DayOfYearWidget.class);
    }
  }

  // OnSeekBarChangeListener

  @Override
  public void onProgressChanged(SeekBar seekBar, int progress,
      boolean fromUser) {
    seekbarInfo.setText(getContext().getString(R.string.int_slash_int,
        progress, seekBar.getMax()));
  }

  @Override
  public void onStartTrackingTouch(SeekBar seekBar) {
  }

  @Override
  public void onStopTrackingTouch(SeekBar seekBar) {
  }
}
Java2html
Der Wertebereich einer SeekBar beginnt bei 0. setMax() legt den größten zulässigen Wert fest. setOnSeekBarChangeListener() registriert einen Listener, der bei Bedarf über Änderungen informiert. Die beiden Methoden setProgress() und getProgress() setzen bzw. liefern den aktuellen Wert.

No comments:

Post a Comment