Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> Android開發教程 >> Android 在Java代碼中設置style屬性(以ProgressBar為例)

Android 在Java代碼中設置style屬性(以ProgressBar為例)

編輯:Android開發教程

在andriod開發中,很大一部分都要與資源打交道,比如說:圖片,布局文件,字符串,樣式等等。這給我們想要開發一些公共的組件帶來很大的困難,因為公共的組件可能更願意以jar包的形式出現。但是java的jar包中只允許出現java代碼而不能出現資源。

當我們想要以jar包的形式提供我們自己開發的公共組件時,我們就需要把以代碼的形式創建資源。

下面提供一個使用全Java代碼的形式創建一個ProgressBar。

ProgressBar默認的樣式是一個圈圈,我們要想其顯示為進度條的樣式可以在布局文件中使用如下代碼:

<ProgressBar
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    style="?android:attr/progressBarStyleHorizontal"  />

這部分的代碼就是使得ProgressBar由轉圈圈的樣式變成進度條的樣式。使用這種方式創建的ProgressBar不能包含在jar包中。

同樣我們也可以使用純代碼的形式創建ProgressBar對象,如下:

...
ProgressBar progressBar = new ProgressBar(context);
LineanerLayout layout = new LinearLayout(context);
layout.addView(progressBar, new LayoutParam(LayoutParam.FILL_PARENT, LayoutParam.FILL_PARENT));
....

這樣就使用純代碼的方式創建了一個ProgressBar對象,但是他還只是默認的樣式一個不停的轉的圈圈。

這時我們可能都會想到好像沒有設置樣式。我們可以把之前的那個樣式設進去,但是我們找遍API發現View並沒有提供任何給我們設置樣式的方法。

其實樣式就是通過一種方式給一個View或一組View設置一些共同的屬性值,所以不可能能使用代碼來設置。

我們可以看下progressBarStyleHorizontal樣式中給View設置了哪些屬性,我們找到framework下的res目錄下的values/Theme.xml文件,搜索progressBarStyleHorizontal會發現如下行:

<item name="progressBarStyleHorizontal">@android:style/Widget.ProgressBar.Horizontal</item>

該主題對應的Widget樣式是Widget.ProgressBar.Horizontal,我們在同樣的的目錄下打開style.xml文件,搜索該樣式,可以找到如下代碼:

  <style name="Widget.ProgressBar.Horizontal">
        <item name="android:indeterminateOnly">false</item>
        <item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
        <item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
        <item name="android:minHeight">20dip</item>
        <item name="android:maxHeight">20dip</item>
    </style>

也就是progressBarStyleHorizontal樣式實際上就是設置了如上的屬性,我們直接在布局文件中把如上的值設進去,代碼看起來如下:

<ProgressBar
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:indeterminateOnly="false"
    android:progressDrawable="@android:drawable/progress_horizontal"
    android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal"
    android:minHeight="20dip"
    android:maxHeight="20dip" />

這時運行我們的程序,發現ProgressBar已從圈圈變成進度條的樣式。這時我們可以在代碼中把這些屬性設成布局文件中的值,純Java代碼看起來應該如下面的那樣:

    ProgressBar progressBar = new ProgressBar(this);
    progressBar.setIndeterminate(false);
    progressBar.setProgressDrawable(getResources().getDrawable(android.R.drawable.progress_horizontal));
    progressBar.setIndeterminateDrawable(getResources().getDrawable(android.R.drawable.progress_indeterminate_horizontal));
    progressBar.setMinimumHeight(20);

    LinearLayout layout = new LinearLayout(this);
    layout.addView(progressBar, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    setContentView(layout);

這時我們發現ProgressBar確實變成了橫條,但並沒有顯示成進度條的樣子,我們仔細對比一下純Java代碼和xml布局文件之間差異,我們發現android:indeterminateOnly="false"和 progressBar.setIndeterminate(false);並不完全一樣布局文件的屬性有一個Only結尾但代碼中並沒有,我們查找Api發現並沒有setIndeterminateOnly這樣的一個方法。

我們打開ProgressBar的源代碼,找到.setIndeterminate(false) 方法,方法的代碼如下:

 public synchronized void setIndeterminate(boolean indeterminate) {
        if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
            mIndeterminate = indeterminate;
 
            if (indeterminate) {
                // swap between indeterminate and regular backgrounds
                mCurrentDrawable = mIndeterminateDrawable;
                startAnimation();
            } else {
                mCurrentDrawable = mProgressDrawable;
                stopAnimation();
            }
        }
    }

我們這時候可以發現Indeterminate和IndeterminateOnly並不是同一個東西,這時我們應該想的到,只要我們把IndeterminateOnly的值變成false就可以使ProgressBar變成進度條的樣式,我們查找所有的代碼,發現並沒有提供相應的公開方法來修改該屬性的值。

也就是說,我們討論了那麼久發現根本就無法通過純代碼的形式來創建一個進度條樣式的ProgressBar.

但是。。。

不就是改變一個類的私有變量的值嘛,Java的封裝性其實並沒有我想的那麼好,我們完全可以通過反射機制來修改一個對象的私有變量的值,由於該文章並不是討論反射的的文章,所以這裡只給出通過反射來修改私有變量值的代碼,但並不作詳細的說明:

我們創建一個新的類,叫BeanUtils.java

類得內容看其來如下:

public class BeanUtils {
    private BeanUtils() {
    }
    /**
     * 直接設置對象屬性值,無視private/protected修飾符,不經過setter函數.
	 *URL:http://www.bianceng.cn/OS/extra/201609/50417.htm
     */
    public static void setFieldValue(final Object object, final String fieldName, final Object value) {
        Field field = getDeclaredField(object, fieldName);
 
        if (field == null)
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
 
        makeAccessible(field);
 
        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
        Log.e("zbkc", "", e);
        }
    }
 
    /**
     * 循環向上轉型,獲取對象的DeclaredField.
     */
    protected static Field getDeclaredField(final Object object, final String fieldName) {
        return getDeclaredField(object.getClass(), fieldName);
    }
 
    /**
     * 循環向上轉型,獲取類的DeclaredField.
     */
    @SuppressWarnings("unchecked")
    protected static Field getDeclaredField(final Class clazz, final String fieldName) {
        for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                // Field不在當前類定義,繼續向上轉型
            }
        }
        return null;
    }
 
    /**
     * 強制轉換fileld可訪問.
     */
    protected static void makeAccessible(Field field) {
        if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
            field.setAccessible(true);
        }
    }
}

該工具提供一個共有的方法:public static void setFieldValue(final Object object, final String fieldName, final Object value)來修改一個對象的私有變量的值:

這時我們的ProgressBar代碼看起來應該如下:

    ProgressBar progressBar = new ProgressBar(this);
    BeanUtils.setFieldValue(progressBar, "mIndeterminateOnly", new Boolean(false));
    progressBar.setIndeterminate(false);
    progressBar.setProgressDrawable(getResources().getDrawable(android.R.drawable.progress_horizontal));
    progressBar.setIndeterminateDrawable(getResources().getDrawable(android.R.drawable.progress_indeterminate_horizontal));
    progressBar.setMinimumHeight(20);
    LinearLayout layout = new LinearLayout(this);
    layout.addView(progressBar, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    setContentView(layout);

到此為止我們終於使用純java代碼的方式創建了一個ProgressBar的進度條樣式。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved