首页

源码搜藏网

首页 > 安卓源码 > 技术博客 >

使用Java和XML为Android创建自己的控件

创建时间:2018-08-08 23:24  浏览

介绍

在Android中,我们有很多方法将布局“分组”在一起,使它们可以重复使用。在我们的XML设计中有一个<include>Tag(以及鲜为人知的<merge>),它只包含当前版本中的另一个布局Fragments,当然,我们可以随时从任何基类派生出来,比如ViewLinearLayout

本文将深入探讨后者:

本文的范围是扩展自己的布局的控件,因此我们将从匹配的基类(a LinearLayout或a)派生RelativeLayout,具体取决于我们的自定义布局的构建方式。

我将在这里使用我自己的一个控件作为示例,向您展示它是如何完成的。这个控件是一个简单的工具栏,有四个按钮,支持我的软件标签的一些标准功能,比如给我发电子邮件,打开我的G +页面,在Google Play上打开我的开发者页面以及评价当前正在运行的应用程序。

它非常简单,因此在文章中进行分析是一个很好的选择。

在运行时,我的控件如下所示:

使用Java和XML为Android创建自己的控件

这是从我的一个使用黑暗主题的应用程序的屏幕截图中获取的。

XML设计中的声明:

<mbar.ui.controls.MbarBar

   android:id="@+id/contact_mbar_button_frame"

   android:layout_width="wrap_content"

   android:layout_height="wrap_content"

   android:layout_below="@+id/contact_mbar_credit_text"

   android:layout_centerHorizontal="true"

   android:layout_marginTop="@dimen/mbar_default_control_distance"

   mbar:barSize="small"/>

可能有不同的方法来实现这一目标:

当然,我们将采用本文中的第三种方法。您可以在此XML代码段中看到的是控件至少使用一个自定义属性:barSize它是一个enum类型属性,知道值“ small”(0)和“ large”(1)。我们将很快创建它,以及第二个自定义属性showTitle,一个简单的布尔值。

我们假设您的库/项目是使用minAPI 17设置的

第1步:创建您的控件类

最好的事情是:创建你的类并决定你的基类是什么。在我们的例子中,这很简单LinearLayout

你需要知道什么

有几个构造函数可用,并不是所有构造函数都需要提供,但我总是试图尽可能完全覆盖基类。

所以,当你开始上课时extends LinearLayout,有4个构造函数可用:

public class MbarBar extends LinearLayout {
   private @MbarBarSize int barSize = MbarBarSize.SMALL;
   private boolean showTitle = true;
   
   // <editor-fold desc="Constructors">
   public MbarBar(Context context) {
      super(context);
      init(null, 0, 0);
   }
   
   public MbarBar(Context context, @Nullable AttributeSet attrs) {
      super(context, attrs);
      init(attrs, 0, 0);
   }
   
   public MbarBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init(attrs, defStyleAttr, 0);
   }
   
   @TargetApi(21)
   public MbarBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
      super(context, attrs, defStyleAttr, defStyleRes);
      init(attrs, defStyleAttr, defStyleRes);
   }
   // </editor-fold>

你可以看到,我将它们全部重定向到一个init(...)方法。我们将稍后介绍一下,让我们现在专注于构造函数。

@TargetApi(21)第4 构造函数周围有一个注释,因为这个注释只能在21+以上。

系统提供给构造函数的值是多少?

第一条规则:将它们传递给超级班级,除非你有充分的理由,不要这样做!

第二:对于我们的开发人员,第二个参数AttributeSet是最感兴趣的,因为这个参数包含来自XML的指定属性,包括我们的自定义属性 barSizeshowTitle所以这已经揭开了第一个谜团:我们如何从XML获取值到我们的控制?答案是:通过AttributeSet当我们讨论该init(...)方法时,我们如何从中获取我们的价值

将xml-enum值映射到代码值

@interfaces非常喜欢那些,所以我创造了一个barSize如果您不知道它是什么:它或多或少是将整数或字符串组合在一起的另一种方法。Android SDK在很多方面做到了这一点,而且你遇到过它们。就像一个简单的例子:每当你设置某些东西时,View.VISIBLE或者View.GONE你正在接触其中一个。

在课程的顶部,您会看到声明:

private @MbarBarSize int barSize = MbarBarSize.SMALL;

这与XML设计中的这一行相关:

mbar:barSize="small"

稍后我们讨论这个自定义属性的声明时,您会看到术语“ small”和“ large”代表值“ 0”和“ 1”。现在,我们当然希望用相同的名称(SMALL和LARGE处理Java中的这些值,我们不想使用01

那么这是什么@MbarBarSize以及它做了什么?@annotation讲述这个int变量只能存放在定义的值@MbarBarSize如果您尝试分配其他内容,则会收到lint警告。

要为成员宣布此类限制,会发布@interface声明。MbarBarSize定义为:

@Retention(RetentionPolicy.CLASS)
public @interface MbarBarSize {
   int SMALL = 0;
   int LARGE = 1;
}

通过这样的声明,您可以分配我称之为value-restrictionvalue-constraint通常允许其他值的数据类型。

的RetentionPolicy

了解何时使用哪个策略非常重要。有三种政策可供选择:

第2步:定义自定义属性

好的,我们已经看到,我们如何将属性值映射到我们的Java代码,但该属性是如何定义的

您可以通过将名为attrs.xml的文件添加项目的values文件夹创建自定义属性右键单击values项目资源管理器中节点,然后选择“ 新建” - >“ 值资源文件”将文件命名为attrs.xml

使用Java和XML为Android创建自己的控件

在此文件中,您可以创建自定义属性。语法并不令人惊讶且易于理解。我在这里向您展示MbarBar控件的完整属性集

<declare-styleable name="MbarBar">
   <attr name="barSize" format="enum">
      <enum name="small" value="0"/>
      <enum name="large" value="1"/>
   </attr>
   <attr name="showTitle" format="boolean"/>
</declare-styleable>

styleable在此处声明了一个资源,这将使XML设计器可以使用它。

有几种格式可供选择,这篇文章的范围太远,无法在这里覆盖它们,但enum格式是最有趣的格式之一,我们将看一下:

然后,声明了两个自定义属性:

第3步:将各个部分组合在一起:init(...)方法

因此,现在您已经定义了自定义属性,您已经了解了它在XML布局中的外观,让我们将它们放在一起并查看AttributeSet以获取开发人员在XML中输入的值。

方法首先,后来说明:

private void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
   if (attrs != null) {
      TypedArray array = getContext().getTheme().obtainStyledAttributes
                         (attrs, R.styleable.MbarBar, defStyleAttr, defStyleRes);
      barSize = array.getInt(R.styleable.MbarBar_barSize, 0);
      showTitle = array.getBoolean(R.styleable.MbarBar_showTitle, true);
   }
   
   switch (barSize) {
      case MbarBarSize.SMALL:
         View smallMe = inflate(getContext(), R.layout.mbar_button_frame_small, this);
         break;
      case MbarBarSize.LARGE:
         View largeMe = inflate(getContext(), R.layout.mbar_button_frame, this);
         break;
   }
   
   setTitleBarVisibility();
   connectListeners();
}

其中一个构造函数(第一个)将null作为attrs值发送给此方法,因此我们需要null-check。在这种情况下,控件将在默认情况下使用所有值:barSize=SMALLshowTitle=true(参见本文中的第一个代码块 - 构造函数,这是类成员的设置方式)。

这里最重要的部分是从XML获取属性。这是通过该方法完成的,该方法obtainStyledAttributes与我们当前的主题相关联context正如我们所得到的LinearLayout,我们有一个getContext()可用方法,所以我们不需要参数或其他方法来获得有效的上下文。我们已经有一个。

参数是:

这个电话后,我们可以为我们将访问同样简单的方式访问我们的属性ExtrasBundle随着getIntgetBoolgetWhatYouNeed非常简单的界面。这些调用中的第二个参数是default-if-not-found。

接下来,有一个switch 声明,膨胀两个预定义布局之一(小和大按钮框架)。这些布局没有什么特别之处,它们也被设计为任何其他布局。只是一堆图像和文本视图。标准。您可以像充气的任何其他布局一样给它充气。

然后调用一些其他支持方法,如隐藏标题栏和连接单击侦听器,但它们不是本文的范围。我们想用自定义属性创建自定义控件:)。

很酷的事:这在设计时已经可见了!如果您打开了预览窗口,则在布局时看到设计已膨胀!

如果您更改XML设计器中的任何自定义属性(例如设置“ showTitle”到“ false”),它会立即反映在布局中,如您所料。

使用Java和XML为Android创建自己的控件

我们创造了什么

最后一件事

当您第一次使用自定义控件时,不要感到困惑,在键入自定义属性的名称时,您在XML中没有智能感知!

您需要知道在android:命名空间中找不到属性,也不在app:命名空间中找不到属性您将为此添加您喜欢的任何命名空间名称(如果是此控件,您可以在我使用的顶部XML中看到mbar:)。

当您开始键入新的命名空间名称时,Android Studio会让您插入...

xmlns:mbar="http://schemas.android.com/apk/res-auto"

...使用Alt + Enter。接受(=按Alt + Enter)。然后您的自定义属性可用此前缀。

所以...我们在这里!

我希望这篇文章可以帮助您完成自定义控件的第一步,并使该部分失去神秘感。

欢迎评论一如既往,我会尽力回答任何问题!

上一篇:从Android资源中读取SQLite数据库的方法
下一篇:一个使用MVP模式的简单图像获取应用程序实现

相关内容

热门推荐