月度归档:2011年12月

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

android.intent.action.MAIN与android.intent.category的作用

在android和ophone的应用程序可以有多个Activity,每个Activity是同级别的,那么在启动程序时,最先启动哪个Activity呢?

有些程序可能需要显示在程序列表里,有些不需要。怎么定义呢?

android.intent.action.MAIN决定应用程序最先启动的Activity 。
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。

因为你的程序可能有很多个activity,
只要xml配置文件中有这么一个intent-filter,而且里面有这个launcher,那么这个activity就是点击程序时最先运行的那个activity。

如果只有一个Activity,没有这两句也可以。

flex中设置背景色或背景图片Fill background image or color in Group using Rect

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:HGroup width="100%" height="100%">
        <s:Group width="50%" height="100%">
            <s:Rect width="100%" height="100%"
                    horizontalCenter="0"
                    verticalCenter="0"
                    topLeftRadiusX="5"
                    topLeftRadiusY="5"
                    topRightRadiusX="5"
                    topRightRadiusY="5">
                <s:fill>
                    <s:BitmapFill fillMode="repeat" source="@Embed(source='flag.png')"/>
                </s:fill>
            </s:Rect>
        </s:Group>
        <s:Group width="50%" height="100%">
            <s:Rect width="100%" height="100%"
                    horizontalCenter="0"
                    verticalCenter="0"
                    topLeftRadiusX="5"
                    topLeftRadiusY="5"
                    topRightRadiusX="5"
                    topRightRadiusY="5">
                <s:fill>
                    <s:SolidColor alpha="0.5" color="#8811dd"/>
                </s:fill>
            </s:Rect>
        </s:Group>
    </s:HGroup>
</s:Application>

效果如下:
[swfobj src=”http://www.sheng00.com/wp-content/uploads/2011/12/BackgroundFill.swf”]

Flex/Air Reading application settings

Reading the application descriptor file

You can read the application descriptor file of the currently running application, as an XML object, by getting the applicationDescriptor property of the NativeApplication object, as in the following:

var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor;

You can then access the application descriptor data as an XML (E4X) object, as in the following:

var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXml.namespace();
var appId = appXml.ns::id[0];
var appVersion = appXml.ns::version[0];
var appName = appXml.ns::filename[0];
air.trace("appId:", appId);
air.trace("version:", appVersion);
air.trace("filename:", appName);

For more information, see The application descriptor file structure.

 

var fileTypes:XML = appXml.ns::fileTypes[0];

                    for each ( var fileType:XML in fileTypes.ns::fileType ) {

                        trace(fileType.ns::name);

                    }