Android 在Java代码中设置style属性(以ProgressBar为例)

在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的进度条样式。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索progressbar
, linearlayout动态布局
, 样式
, 代码
, 属性
, android progressbar
, getdrawable过时
, android 反射
, android 样式
, 一个
, Style.xml
, Style.xml应用
, Style.xml实例应用
android进度条样式
android style 属性、android中style属性、android获取style属性、progressbar style、progressbar样式style,以便于您获取更多的相关知识。

时间: 2024-11-03 14:23:53

Android 在Java代码中设置style属性(以ProgressBar为例)的相关文章

字体颜色-android java代码中设置radiobutton选中与为选中颜色

问题描述 android java代码中设置radiobutton选中与为选中颜色 tab_rb_b.setTextColor(MainActivity.this.getResources().getColor(R.drawable.main_text_color)); 其中R.drawable.main_text_color是自己写好的 颜色改变的xml <!-- not selected --> 但是设好之后 颜色并没有随选中而改变,只是一直都是为选中状态的颜色. 哪位大神知道是怎么回事吗

colors-无法实现在java代码中设置radiobutton颜色变换

问题描述 无法实现在java代码中设置radiobutton颜色变换 我在res/color文件夹下写了一个selector,在java中setTextColor引用时无效果. 本人新手,还请各位大大指教~ 以下是关键代码 res/color/textcolor.xml <?xml version="1.0" encoding="utf-8"?> <item android:state_checked="true" androi

动态-android如何在代码中给组件设置style?

问题描述 android如何在代码中给组件设置style? RT,不要提TextView了,全部都是告诉我TextView.setTextAppearance(),我要的是别的组件,比如LinearLayout之类的,如何在代码中设置他的style 我看了下源代码,style都是在初始化的时候通过TypedArray解析style然后一条条属性加进去的,那么有没有类似style这样的方法,可以动态设置的 没有C币了,多多包涵下,谢谢了 解决方案 参考Android: set view style

图文讲解Android的ImageView类中的ScaleType属性设置_Android

ScaleType设置图解图文相配很清晰的看出每个属性的效果, 感觉 CENTER_CROP 比较有用,长宽自动适应 ImageView ,整个图片自动缩略填充整个区域且居中显示(高宽不一定是view的尺寸),以前用JS在网页上实现的,在 android上一开始还在想要用java来自己实现这个效果太麻烦了,没想到系统自带方便多了 ImageView的Scaletype决定了图片在View上显示时的样子,如进行何种比例的缩放,及显示图片的整体还是部分,等等. 设置的方式包括: 1. 在layout

android代码布局-android 代码中设置控件的垂直居中和两个控件之间的距离。

问题描述 android 代码中设置控件的垂直居中和两个控件之间的距离. 因为数据是动态的 所以所有的控件和布局都是在java代码里面设置 怎样才能让一个控件垂直居中 还有两个控件之间的距离又是怎么设置的啊 求高手指点啊 最好能给点代码 我是新手 说的太笼统了 看不太懂 谢谢了 解决方案 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT,

android 如何在java代码中方便的调用xml写的布局??

问题描述 android 如何在java代码中方便的调用xml写的布局?? 我想在activity刷新的时候重新生成一些xml写的布局,并放在 "求学"那一栏下: 想问一下有没有什么方便的方法??? 解决方案 可控的话 先加载求学哪里 先设visible为gone. 需要的时候设置为visible 解决方案二: 楼上说得对,先把控件实例化然后把visiblity设为gone 然后调用刷新按钮的时候吧实例传过去,再重新设置visiblity 解决方案三: 一种是隐藏然后显示,最好是用动态

为什么性能优化中,设置style属性会引起reflow?

问题描述 为什么性能优化中,设置style属性会引起reflow? 在学习性能优化的时候,看到repaint和reflow,说每设置一次style就会引起一次reflow.那么如果style设置的时候没有改变元素的几何属性(宽高)的话,为什么还会引起reflow呢? 解决方案 不只宽高,比如边距改变,文本内容改变.位置改变等都会引起reflow. 宽高只是最终表象.但改变宽高的因素有什么.

怎么样让wpf中前台已存在的控件的属性可以在后台代码中设置

问题描述 怎么样让wpf中前台已存在的控件的属性可以在后台代码中设置 怎么样让wpf中前台已存在的控件的属性可以在后台代码中设置,比如说xaml中已经存在一个border,我想要在后台代码中初始化他的旋转角度 解决方案 这些属性是可以在后台代码中设置的,直接在后台.cs文件里写就是了 解决方案二: 好像不能把,比如说 在后台代码怎么修改Angle属性呢 解决方案三: http://www.cnblogs.com/slowhand/archive/2013/05/13/3076259.html 亲

Android中,怎么在代码中实现“toRightof”属性?

问题描述 Android中,怎么在代码中实现"toRightof"属性? 所属的布局是Relative,就是不会用代码根据外界条件动态实现这个属性.怎么让A控件用代码实现在B控件右边的功能? 解决方案 RelativeLayout layout = new RelativeLayout(this); TextView tv1 = new TextView(this); tv1.setText("A"); TextView tv2 = new TextView(thi