Android9编程十二:代码操作控件

上一篇: Android9编程十一:各种Layout控件

所有的控件都是从类View派生,所以控件也被叫做View。各种Layout控件当然也是View了,但由于其作用特殊,所以我们单独称它们为Layout(同时我们把一个UI资源文件件有时也称做layout资源,因为它在res/layout组下)。

Activity中创建界面

Activity虽然代表一个页面,但是它却不是View,然而它却能管理View们。我们可以使用代码将一个Activity上的控件们创建出来并摆放好来构成Activity的界面,但是太麻烦,以后的改动也非常难,所以通常都是在layout资源中定义Activity的界面。App在显示一个Activity前,会把Layout中定义界面创建出来,设置给Activity,之后再把Activity显示出来,这样我们就看到了Activity的样子,所以Activity的内容是由它里面的控件们组合出来的。

实际上从layout资源创建界面并设置给Activity这件事,App并不会自动做,需要我们写代码完成,只需要调用Acitivity的一个方法setContentView()即可。这个方法需要一个参数,就是layout资源文件的id。这个方法需要在什么时机调用呢? 法应在Activity被创建之后,但还未显示出来之前调用。最适合的地方就是Activity的onCreate()方法。打开你的MainActivity类看一下,是不是有onCreate()方法:

并且setContentView()方法是不是被调用了? 在onCreate()方法被调用之后经过不长的时间,Activity就被显示出来,由于显示之前已把控件都创建并加载了,所以我们就看到了Activity的界面。当然这些代码Android Studio已帮我们添加了,所以不需要我们手动写了,但它们也不是SDK中的类封装好的,所以还是相当于我们手动添加的。

setContentView()的实参是R.layout.activity_main,它是一个整数常量,它是layout型资源文件activity_main.xml的id。R是一个类,是Gradle处理项目中的资源文件后自动产生的,我们不能改动它的内容。可以看到layout资源文件的id名与文件名相同,而文件的扩展名被忽略。既然文件名要成为类中常量的名字,所以文件名当然不能以数字开头了。

资源id一般是这样命名的:“R.资源类型.id名”,比如引用一个资源中定义的字符串,如果其id为“xxx”,就用“ R.string.xxx ”;引用一个图片(其id也为“xxx”),就用“ R.drawable.xxx ”,而引用layout资源(比如activity_main.xml)中的某个控件时(控件id也为“xxx”),就用“ R.id.xxx ”。总之就是,如果引用的是一个资源文件,“R”后面是其类别,如果是资源中的一个元素(比如layout资源中的一个控件),“R”后面是“id”。

Activity的父类

所有Activity的祖宗是类Activity。但我们看到MainActivity类的父类是AppCompatActivity。AppCompatActivity当然也是从Activity类派生的,它对旧版本Android系统的兼容性好,所以现在推荐此类为我们定义的Activity的父类,这样你的App才有可能运行在比较低的Android系统中,也就是有更多的手机可以运行你的App。

四大组件

Activity被称作Android系统中的四大组件之一。这四大组件分别是:Activity、BroardcastReceiver(广播接收者)、Service(服务)和ContentProvider(内容提供者)。

这四大组件后面都会介绍,现在你只需要记住,四大组件有个明显的特征:就是不能通过new直接实例化,而必须由Android系统创建它们。但前提是能让系统能找到这四大组件的类定义。如果你自定义一个四大组件的类,你必须在你的App的Manifest(名单)文件中声明它,这样系统才能找到这个类,才能实例化它。看一下我们的AndriodzManifest文件的内容:

被红框框起来的就是我们App中当前唯一的Activity的声明。属性“android:name”的值“.MainActivity”是Activity的类名,此处省略了包名,但是前面的“.”不能省。其实有了这个类名,系统就可以通过反射的方式把Activity创建出来了。至于“”元素的作用,后面会讲到。

如果你只创建了Activity的类,而没有在Manifest文件中声明它,那你的Activity是不能启动的。

代码中操作控件

现在运行我们的App的话,看到的将是登录界面:

我们正好可以通过登录功能来演示代码如何操作控件。比如要验证是否能登录,我们必须获取用户输入的用户名和密码,什么时候获取呢? 登录这个动作是在用户点了登录按钮之后执行的,所以需要响应按钮的点击事件,在响应事件的回调方法中获取用户名和密码。

无论怎样,只有先获取控件,才能操作它。

获取View

还记得我们为控件指定的ID吗?

在代码中就是通过这个ID来获得控件对象的。获得用户名这个EditText控件的代码如下:

EditText editTextName = (EditText) findViewById(R.id.editTextName);

下面我们就可以用editTextName 这个变量来操作所引用的控件对象了。

获取控件用的是Activity的findViewById()方法,其参数是控件的ID。它的返回类型是View,而我们知道这里实际上它是一个EditText类型(到底是什么类型需要去界面设计器中查看),所以我们进行了强制类型转换(EditText是View的一个子类)。

现在得到了这个控件,就可以对它为所欲为了,比如可以把在属性编辑器中设置的属性改用为代码来设置,这样也让我们体会到:一切的本质还是代码。

首先让我们在属性编辑器中把用户名输入控件的hint属性清空(文件是activity_main.xml,别搞错了),这样就看不到提示了:

然后在代码中这样写: editTextName.setHint("请输入用户名");

那么这行代码应该放在什么位置呢? 我们一般希望在Activity一显示出来就能看到EditText控件中的hint,所以应在界面显示之前就设置,当然控件也必须已被创建,所以应放在控件创建之后,显示之前,最合适的位置就是Activity的onCreate()方法中的setContentView()这一句之后。现在Activity的onCreate方法是这样的:

注意!代码中有标志符是红色的!这表示找不到这个标志符的定义。类名,方法名,变量名等统称标志符,这个错误表示“叫做EditText的类或方法或变量没有定义”。跟据Java的命名习惯,开头字母大写的是类或接口,所以这里是类定义找不到。其原因可能是类真的没有定义,也可能是已定义了而没有导入。这里就是没有导入造成的,解决方法是Import这个类,你不用去查这个类所在的包,你可以试一下快捷键“Alt+Enter”,看看它能不能帮你解决错误。当我按了快捷键后问题解决,可以看到导入了类:import android.widget.EditText;

一般你这样解除源码中提示的错误:在红色文本内点一下鼠标,就会出现“Alt+Enter”的提示,这个快捷键大部分情况下都能帮你解决问题。它有时也会弹出多项解决方法让你选择,那你就要看仔细了,别选错了。现在的代码是这样的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //从layout资源文件中加资控件并设置给Activity。
    setContentView(R.layout.activity_main);

    //用id找到用户输入控件
    EditText editTextName = (EditText) findViewById(R.id.editTextName);
    //用代码设置它的提示
    editTextName.setHint("请输入用户名");
}

运行之:

可以看到,在实际运行中,用户名输入控件中依然有提示,说明代码起作用了!在代码中设置提示的方法是setHint(),它符合JAVA中getter和setter的命名规则,setHint对应的属性名就是“hint”,所以在界面设计器中就是设置“hint”属性。

摘自《Android9编程通俗演义》-清华大学出版社,京东淘宝及各大书店有售)