Customized SeekBarPreference

Android没有提供SeekBarPreference,所以只有自己写一个了。。

SeekBarPreference.java

package com.sheng00.BatteryStatus;
import com.sheng00.BattaryStatus.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {
    private final String TAG = getClass().getName();
    private static final String ANDROIDNS="http://schemas.android.com/apk/res/android";
    private static final String SHENG00NS="http://sheng00.com";
    private static final int DEFAULT_VALUE = 50;
    private int mMaxValue      = 100;
    private int mMinValue      = 0;
    private int mInterval      = 1;
    private int mCurrentValue;
    private String mUnitsLeft  = "";
    private String mUnitsRight = "";
    private SeekBar mSeekBar;
    private TextView mStatusText;
    public SeekBarPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPreference(context, attrs);
    }
    public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initPreference(context, attrs);
    }
    private void initPreference(Context context, AttributeSet attrs) {
        setValuesFromXml(attrs);
        mSeekBar = new SeekBar(context, attrs);
        mSeekBar.setOnSeekBarChangeListener(this);
        mSeekBar.setMax(mMaxValue - mMinValue);
    }
    private void setValuesFromXml(AttributeSet attrs) {
        mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", 100);
        mMinValue = attrs.getAttributeIntValue(SHENG00NS, "min", 0);
        mUnitsLeft = getAttributeStringValue(attrs, SHENG00NS, "unitsLeft", "");
        String units = getAttributeStringValue(attrs, SHENG00NS, "units", "");
        mUnitsRight = getAttributeStringValue(attrs, SHENG00NS, "unitsRight", units);
        try {
            String newInterval = attrs.getAttributeValue(SHENG00NS, "interval");
            if(newInterval != null)
                mInterval = Integer.parseInt(newInterval);
        }
        catch(Exception e) {
            Log.e(TAG, "Invalid interval value", e);
        }
    }
    private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
        String value = attrs.getAttributeValue(namespace, name);
        if(value == null)
            value = defaultValue;
        return value;
    }
    @Override
    protected View onCreateView(ViewGroup parent){
        RelativeLayout layout =  null;
        try {
            LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            layout = (RelativeLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
        }
        catch(Exception e)
        {
            Log.e(TAG, "Error creating seek bar preference", e);
        }
        return layout;
    }
    @Override
    public void onBindView(View view) {
        super.onBindView(view);
        try
        {
            // move our seekbar to the new view we've been given
            ViewParent oldContainer = mSeekBar.getParent();
            ViewGroup newContainer = (ViewGroup) view.findViewById(R.id.seekBarPrefBarContainer);
            if (oldContainer != newContainer) {
                // remove the seekbar from the old view
                if (oldContainer != null) {
                    ((ViewGroup) oldContainer).removeView(mSeekBar);
                }
                // remove the existing seekbar (there may not be one) and add ours
                newContainer.removeAllViews();
                newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
        }
        catch(Exception ex) {
            Log.e(TAG, "Error binding view: " + ex.toString());
        }
        updateView(view);
    }
    /**
     * Update a SeekBarPreference view with our current state
     * @param view
     */
    protected void updateView(View view) {
        try {
            RelativeLayout layout = (RelativeLayout)view;
            mStatusText = (TextView)layout.findViewById(R.id.seekBarPrefValue);
            mStatusText.setText(String.valueOf(mCurrentValue));
            mStatusText.setMinimumWidth(30);
            mSeekBar.setProgress(mCurrentValue - mMinValue);
            mSeekBar.setEnabled(this.isEnabled());
            TextView unitsRight = (TextView)layout.findViewById(R.id.seekBarPrefUnitsRight);
            unitsRight.setText(mUnitsRight);
            TextView unitsLeft = (TextView)layout.findViewById(R.id.seekBarPrefUnitsLeft);
            unitsLeft.setText(mUnitsLeft);
        }
        catch(Exception e) {
            Log.e(TAG, "Error updating seek bar preference", e);
        }
    }
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        int newValue = progress + mMinValue;
        if(newValue > mMaxValue)
            newValue = mMaxValue;
        else if(newValue < mMinValue)
            newValue = mMinValue;
        else if(mInterval != 1 && newValue % mInterval != 0)
            newValue = Math.round(((float)newValue)/mInterval)*mInterval;
        // change rejected, revert to the previous value
        if(!callChangeListener(newValue)){
            seekBar.setProgress(mCurrentValue - mMinValue);
            return;
        }
        // change accepted, store it
        mCurrentValue = newValue;
        if (mStatusText != null) {
            mStatusText.setText(String.valueOf(newValue));
        }
        persistInt(newValue);
    }
    public void onStartTrackingTouch(SeekBar seekBar) {}
    public void onStopTrackingTouch(SeekBar seekBar) {
        notifyChanged();
    }
    @Override
    protected Object onGetDefaultValue(TypedArray ta, int index){
        int defaultValue = ta.getInt(index, DEFAULT_VALUE);
        return defaultValue;
    }
    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if(restoreValue) {
            mCurrentValue = getPersistedInt(mCurrentValue);
        }
        else {
            int temp = 0;
            try {
                temp = (Integer)defaultValue;
            }
            catch(Exception ex) {
                Log.e(TAG, "Invalid default value: " + defaultValue.toString());
            }
            persistInt(temp);
            mCurrentValue = temp;
        }
    }
}

这时需要在layout里写布局文件
seek_bar_preference.xml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/widget_frame"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:paddingLeft="15dp"
  android:paddingTop="5dp"
  android:paddingRight="10dp"
  android:paddingBottom="5dp"
  >
  <TextView android:id="@android:id/title"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="22dp"
    android:typeface="sans"
    android:textStyle="normal"
    android:textColor="#ffffff"
  ></TextView>
  <TextView android:id="@android:id/summary"
    android:layout_alignParentLeft="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@android:id/title"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefUnitsRight"
    android:layout_alignParentRight="true"
    android:layout_below="@android:id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefValue"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toLeftOf="@id/seekBarPrefUnitsRight"
    android:layout_below="@android:id/title"
    android:gravity="right"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefUnitsLeft"
    android:layout_below="@android:id/title"
    android:layout_toLeftOf="@id/seekBarPrefValue"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  ></TextView>
  <LinearLayout android:id="@+id/seekBarPrefBarContainer"
    android:layout_alignParentLeft="true"
    android:layout_alignParentBottom="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@android:id/summary">
  </LinearLayout>
</RelativeLayout>

然后可以写进我们的activity的布局文件里了:

<com.sheng00.batterystatus.seekbarpreference
  sheng00:unitsright="%"
  sheng00:unitsleft=""
  android:dependency="@string/low_alert_checkbox"
  android:summary=" "
  android:title="@string/low_alert_level"
  sheng00:min="1"
  android:max="50"
  android:key="@string/low_alert_level_key"
  android:defaultvalue="15" />

效果如下图:
device-2011-12-21-115808

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注