10.创建组合控件

10.1 问题

需要通过组合现有的元素来创建自定义的小部件。

10.2 解决方案

(API Level 1)
通过扩展通用的ViewGroup并添加所需的功能就能创建自定义的小部件。创建自定义小部件或可重用用户界面元素的最简单、最实用的方法就是利用Android SDK提供的现有小部件来创建组合控件。

10.3 实现机制

ViewGroup及其子类LinearLayout、RelativeLayout等能帮助你摆放控件的位置,这样你就可以专注于添加所需的功能。

TextImageButton
下面将创建一个Android SDK中没有原生提供的小部件:含有图片或文字的按钮。为了实现这个小部件,我们创建TextImageButton类,这是对FrameLayout的扩展。其中包含一个用于放置文本内容的TextView,以及一个用于放置图片内容的ImageView(参见以下代码)。
自定义TextImageButton小部件

public class TextImageButton extends FrameLayout {

    private ImageView imageView;
    private TextView textView;

    /* 构造函数 */
    public TextImageButton(Context context) {
        this(context, null);
    }

    public TextImageButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TextImageButton(Context context, AttributeSet attrs, int defaultStyle) {
        //通过系统的按钮样式初始化父布局
        // 这样会设置clickable属性和按钮背景来匹配当前的主题
        super(context, attrs, android.R.attr.buttonStyle);
        imageView = new ImageView(context, attrs, defaultStyle);
        //创建子视图
        textView = new TextView(context, attrs, defaultStyle);
        //创建子视图的LayoutParams为WRAP_CONTENT并居中显示
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT,
                    Gravity.CENTER);
        //添加视图
        this.addView(imageView, params);
        this.addView(textView, params);

        //如果有图片,切换到图片模式
        if(imageView.getDrawable() != null) {
            textView.setVisibility(View.GONE);
            imageView.setVisibility(View.VISIBLE);
        } else {
            textView.setVisibility(View.VISIBLE);
            imageView.setVisibility(View.GONE);
        }
    }

    /* 存取器*/
    public void setText(CharSequence text) {
        //切换到文字模式
        textView.setVisibility(View.VISIBLE);
        imageView.setVisibility(View.GONE);
        //设置文字
        textView.setText(text);
    }

    public void setImageResource(int resId) {
        //切换到图片模式
        textView.setVisibility(View.GONE);
        imageView.setVisibility(View.VISIBLE);
        //设置图片
        imageView.setImageResource(resId);
    }

    public void setImageDrawable(Drawable drawable) {
        //切换到图片模式
        textView.setVisibility(View.GONE);
        imageView.setVisibility(View.VISIBLE);
        //设置图片
        imageView.setImageDrawable(drawable);
    }
}

SDK中所有的小部件都有至少两个(通常为3个)构造函数。第一个构造函数的参数只有一个Context,通常用于在代码中新建视图。另外两个构造函数用于将XML转换成视图,XML文件中定义的属性会传递给AttributeSet参数。这里我们用Java的this()符号调用实际完成所有工作的函数,从而实现了这两个构造函数。以这种方式构造自定义控件就确保了我们能在XML布局中定义此视图。如果不实现这两个属性化的构造函数(attributed constructor),就不能在XML布局中使用自定义的控件。
为了让FrameLayout看起来更像一个标准的按钮,我们在构造函数中传入了android.R.attr.buttonStyle属性。这里定义了和当前主题匹配的样式并设置了视图上。这不仅设置了背景来匹配其他的按钮实例,还让视图变得可单击和可获得焦点(因为这些样式就是系统样式的一部分)。只要有可能,都应该从当前主题中加载自定义小部件的外观,从而可轻松定制并与应用程序的其他部分保持统一。
构造函数还创建一个TextView和一个ImageView,将它们放入布局中。向每个子构造函数传递相同的属性集,从而可以正确读取特定于每个构造函数设置的XML属性(例如文字和图片状态)。其他的代码根据属性中传递的数据设置默认的显示模式(文字或图片)。
加入存取器函数是为了方便以后改变按钮的内容。这些函数还负责在内容变化时在文字和图片模式间进行切换。
因为这个自定义的控件并没有在android.view或android.widget包中,所有在XML布局中使用该控件必须使用全名。以下两段代码演示了含有该自定义小部件的Activity。
res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
     <com.examples.customwidgets.TextImageButton
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="Click Me!"
         android:textColor="#000" />
     <com.examples.customwidgets.TextImageButton
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:src="@drawable/ic_launcher" />
</LinearLayout>

使用了新的自定义小部件的Activity

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

注意,我们还是可以使用传统的属性来设置要显示的文字或图片。这是因为我们用属性化构,造函数来构造各个元素(FrameLayout、TextView和ImageView),所以每个视图都会根据自己的需求设置参数,忽略其他参数。
如果我们定义使用该布局的Activity,效果如图所示。
同时显示文字和图片的TextImageButton

猜你喜欢

转载自blog.csdn.net/qq_41121204/article/details/82696802
10.
今日推荐