创建第一个Android Kotlin应用

本教程将创建一个Android Basic Activity Kotlin工程,并实现基本的页面跳转,基于Android Studio 3.6+(本教程实际运行于Android Studio Bumblebee | 2021.1.1 Patch 2)

创建第一个Kotlin应用程序

创建一个新的工程

打开Android Studio,选择Projects>New Project,然后选择Basic Activity.
在这里插入图片描述
点击Next,为应用程序命名(例如:My First App),选择Kotlin语言,然后点击Finish。Android Studio将使用系统中最新的API Level创建应用程序,并使用Gradle作为构建系统,在底部的视窗中可以查看整个过程。

探索Android Studio的界面布局

整个Android Studio工作区包括多个部分,
在这里插入图片描述

创建模拟器

次步骤创建可以运行APP的模拟器,点击Tool>Device Manager或者工具栏上的按钮在这里插入图片描述
点击Create device,弹出创建模拟器的页面,
在这里插入图片描述
选择想要创建模拟器设备(如Pixel 5),点击Next,在系统镜像页面的Recommended标签栏,选择最新镜像,
在这里插入图片描述

然后首先下载镜像(Download),下载完成之后点击Next,完成模拟器命名和更多参数选择,最终点击Finish完成。注意:真实型号机型的模拟器镜像往往十分巨大,如果硬盘空间不足,考虑下载通用模拟器镜像。
在这里插入图片描述

在模拟器上运行应用程序

选择Run>Run ‘app’,在工具栏上可以看到运行程序的一些选择项。
在这里插入图片描述
运行效果:
在这里插入图片描述

查看布局编辑器

在Basic Activity中,包含了基本的导航组件,Android app关联两个fragments,第一个屏幕显示了“Hello first fragment”由FirstFragment创建,界面元素的排列由布局文件指定,查看res>layout>fragment_first.xml,
在这里插入图片描述
查看布局的代码(Code),修改Textview的Text属性,

android:text="@string/hello_first_fragment"

右键该代码,选择Go To > Declaration or Usages,跳转到values/strings.xml,看到高亮文本

<string name="hello_first_fragment">Hello first fragment</string>

修改字符串属性值为“Hello Kotlin!”。更进一步,修改字体显示属性,在Design视图中选择textview_first文本组件,在Common Attributes属性下的textAppearance域,设置相关的文字显示属性,
在这里插入图片描述
查看布局的XML代码,可以看到新属性被应用。

android:fontFamily="sans-serif-condensed"
android:text="@string/hello_first_fragment"
android:textColor="@android:color/darker_gray"
android:textSize="30sp"
android:textStyle="bold"

重新运行应用程序,查看显示效果。

向页面添加更多的布局

本步骤将向第一个Fragment添加更多的视图组件

查看视图的布局约束

fragment_first.xml,查看TextView组件的约束属性:在这里插入图片描述
在约束布局中,每个组件至少需要一个水平方向和一个垂直方向的约束,更多约束布局的内容,请查看ConstraintLayout

添加按钮和约束

从Palette面板中拖动Button到

在这里插入图片描述
调整Button的约束,设置Button的Top>BottonOf textView,

app:layout_constraintTop_toBottomOf="@+id/textview_first" />

随后添加Button的左侧约束至屏幕的左侧,Button的底部约束至屏幕的底部。查看Attributes面板,修改将id从button修改为toast_button(注意修改id将重构代码)

调整Next按钮

Next按钮是工程创建时默认的按钮,查看Next按钮的布局设计视图,它与TextView之间的连接不是锯齿状的而是波浪状的,表明两者之间存在链(chain),是一种两个组件之间的双向联系而不是单向联系。删除两者之间的链,可以在设计视图右键相应约束,选择Delete(注意两个组件要双向删除);
在这里插入图片描述
或者在属性面板的Constraint Widget中移动光标到相应约束点击删除。
在这里插入图片描述
同时,删除Next按钮的左侧约束。

添加新的约束

添加Next的右边和底部约束至父类屏幕(如果不存在的话),Next的Top约束至TextView的底部。最后,TextView的底部约束至屏幕的底部。效果看起来如下图所示:
在这里插入图片描述

更改组件的文本

fragment_first.xml布局文件代码中,找到toast_button按钮的text属性部分

<Button
   android:id="@+id/toast_button"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="Button"

这里text的赋值是一种硬编码,点击文本,左侧出现灯泡状的提示,选择 Extract string resource
在这里插入图片描述
弹出对话框,令资源名为toast_button_text,资源值为Toast,并点击OK。
在这里插入图片描述
于是,在资源文件string.xml定义了字符串,以上操作可以手动在string.xml文件中定义并引用。

<resources>
   ... 
   <string name="toast_button_text">Toast</string>
</resources>

更新Next按钮

在属性面板中更改Next按钮的id,从button_first改为random_button。
在这里插入图片描述
在string.xml文件,右键next字符串资源,选择 Refactor > Rename,修改资源名称为random_button_text,点击Refactor 。随后,修改Next值为Random

添加第三个按钮

向fragment_first.xml文件中添加第三个按钮,位于Toast和Random按钮之间,TextView的下方。新Button的左右约束分别约束至Toast和Random,Top约束至TextView的底部,Buttom约束至屏幕的底部,看起来的效果:
在这里插入图片描述
检查xml代码,确保不出现类似app:layout_constraintVertical_bias这样的属性,即不手动设置偏移量。

完善UI组件的属性设置

更改新增按钮id为count_button,显示字符串为Count,对应字符串资源值为count_button_text。于是三个按钮的text和id属性如下表:
在这里插入图片描述
同时,更改TextView的文本为0。修改后的fragment_first.xml的代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstFragment">

    <TextView
        android:id="@+id/textview_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="sans-serif-condensed"
        android:text="@string/hello_first_fragment"
        android:textColor="@android:color/darker_gray"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/random_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/random_button_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textview_first" />

    <Button
        android:id="@+id/toast_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/toast_button_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textview_first" />

    <Button
        android:id="@+id/count_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/count_button_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/random_button"
        app:layout_constraintStart_toEndOf="@+id/toast_button"
        app:layout_constraintTop_toBottomOf="@+id/textview_first" />
</androidx.constraintlayout.widget.ConstraintLayout>

尝试运行应用程序查看效果。

更新按钮和文本框的外观

添加新的颜色资源

values>colors.xml定义了一些应用程序可以使用的颜色,添加新颜色screenBackground 值为 #2196F3,这是蓝色阴影色;添加新颜色buttonBackground 值为 #BBDEFB

<color name="screenBackground">#2196F3</color>
<color name="buttonBackground">#BBDEFB</color>

设置组件的外观

  1. fragment_first.xml的属性面板中设置屏幕背景色为
android:background="@color/screenBackground"
  1. 设置每个按钮的背景色为buttonBackground
android:background="@color/buttonBackground"

注意:在实验的API level中(31),这种设置并不生效,需修改res/values/themes.xml的style值,添加**.Bridge**。

<style name="Theme.MyFirstApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
  1. 移除TextView的背景颜色,设置TextView的文本颜色为color/white,并增大字体大小至72sp

设置组件的位置

  1. Toast与屏幕的左边距设置为24dp,Random与屏幕的右边距设置为24dp,利用属性面板的Constraint Widget完成设置。
    在这里插入图片描述
  2. 设置TextView的垂直偏移为0.3,
app:layout_constraintVertical_bias="0.3"

拖动左侧的移动条。
在这里插入图片描述

运行应用程序

最终效果如下图:
在这里插入图片描述

添加代码完成应用程序交互

设置代码自动补全

Android Studio中,依次点击File>New Projects Settings>Settings for New Projects…,查找Auto Import选项,在Java和Kotlin部分,勾选Add Unambiguous Imports on the fly
在这里插入图片描述

TOAST按钮添加一个toast消息

打开FirstFragment.kt文件,有三个方法:onCreateView,onViewCreated和onDestroyView,在onViewCreated方法中使用绑定机制设置按钮的响应事件(创建应用程序时自带的按钮)。

binding.randomButton.setOnClickListener {
    findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}

接下来,为TOAST按钮添加事件,使用**findViewById()**查找按钮id,代码如下:

// find the toast_button by its ID and set a click listener
view.findViewById<Button>(R.id.toast_button).setOnClickListener {
   // create a Toast with some text, to appear for a short time
   val myToast = Toast.makeText(context, "Hello Toast!", Toast.LENGTH_LONG)
   // show the Toast
   myToast.show()
}

代码使用了Lambda表达式的机制。

使Count按钮更新屏幕的数字

此步骤向Count按钮添加事件响应,更新Textview的文本显示。
在FirstFragment.kt文件,为count_buttion按钮添加事件:

view.findViewById<Button>(R.id.count_button).setOnClickListener {
   countMe(view)
}

countMe()为自定义方法,以View为参数,每次点击增加数字1,具体代码为:

private fun countMe(view: View) {
   // Get the text view
   val showCountTextView = view.findViewById<TextView>(R.id.textview_first)

   // Get the value of the text view.
   val countString = showCountTextView.text.toString()

   // Convert value to a number and increment it
   var count = countString.toInt()
   count++

   // Display the new value in the text view.
   showCountTextView.text = count.toString()
}

完成第二界面的代码

此步骤将完成按照First Fragment显示数字作为上限,随机在Second Fragment上显示一个数字,即Random按钮的事件响应。效果如下:
在这里插入图片描述

向界面添加TextView显示随机数

  1. 打开fragment_second.xml的设计视图中,当前界面有两个组件,一个Button和一个TextView(textview_second)。
  2. 去掉TextView和Button之间的约束
    在这里插入图片描述
  3. 拖动新的TextView至屏幕的中间位置,用来显示随机数
  4. 设置新的TextView的id为**@+id/textview_random**
  5. 设置新的TextView的左右约束至屏幕的左右侧,Top约束至textview_second的Bottom,Bottom约束至Button的Top
  6. 设置TextView的字体颜色textColor属性为**@android:color/white**,textSize72sptextStylebold
  7. 设置TextView的显示文字为“R
  8. 设置垂直偏移量layout_constraintVertical_bias为0.45

新增TextView最终的属性代码

<TextView
   android:id="@+id/textview_random"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="R"
   android:textColor="@android:color/white"
   android:textSize="72sp"
   android:textStyle="bold"
   app:layout_constraintBottom_toTopOf="@+id/button_second"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toBottomOf="@+id/textview_second"
   app:layout_constraintVertical_bias="0.45" />

更新显示界面文本的TextView(textview_second)

  1. 在fragment_second.xml文件中,选择textview_second文本框,查看text属性,可见
android:text="@string/hello_second_fragment

对应的strings.xml文本为Hello second fragment. Arg: %1$s

  1. 更改该文本框id为textview_header

  2. 设置layout_width为match_parent,layout_height为wrap_content

  3. 设置top,left和right的margin为24dp,左边距和右边距也就是start和end边距。

  4. 若还存在与Button的约束,则删除。

  5. 向colors.xml添加颜色colorPrimaryDark,并将TextView颜色设置为@color/colorPrimaryDark,字体大小为24sp

    <color name="colorPrimaryDark">#3700B3</color>
    
  6. strings.xml文件中,修改hello_second_fragment的值为"Here is a random number between 0 and %d."

  7. 使用Refactor>Renamehello_second_fragment 重构为random_heading

因此,显示界面信息的Textview的代码为:

<TextView
   android:id="@+id/textview_header"
   android:layout_width="0dp"
   android:layout_height="wrap_content"
   android:layout_marginStart="24dp"
   android:layout_marginLeft="24dp"
   android:layout_marginTop="24dp"
   android:layout_marginEnd="24dp"
   android:layout_marginRight="24dp"
   android:text="@string/random_heading"
   android:textColor="@color/colorPrimaryDark"
   android:textSize="24sp"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent" />

更改界面的背景色和按钮布局

  1. 向colors.xml文件添加第二个Fragment背景色的值,修改fragment_second.xml背景色的属性为screenBackground2
<color name="screenBackground2">#26C6DA</color>

在这里插入图片描述

  1. 将按钮移动至界面的底部,完成所有布局之后,如下图所示:
    在这里插入图片描述

检查导航图

本项目选择Android的Basic Activity类型进行创建,默认情况下自带两个Fragments,并使用Android的导航机制Navigation。导航将使用按钮在两个Fragment之间进行跳转,就第一个Fragment修改后的Random按钮和第二个Fragment的Previous按钮。

打开nav_graph.xml文件(res>navigation>nav_graph.xml),形如:
在这里插入图片描述

可以任意拖动界面中的元素,观察导航图的变化。

启用SafeArgs

SafeArgs 是一个 gradle 插件,它可以帮助您在导航图中输入需要传递的数据信息,作用类似于Activity之间传递数据的Bundle。

设置SafeArgs的gradle的脚本步骤可以参考:Navigation API参考文档

  1. 首先打开 Gradle Scripts > build.gradle (Project: My First App)
  2. 找到buildscript脚本中的dependencies章节,添加如下代码
def nav_version = "2.3.0-alpha02"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
  1. 接着打开 Gradle Scripts > build.gradle (Module: app)
  2. apply plugin开头的代码下添加一行
apply plugin: 'androidx.navigation.safeargs.kotlin'
  1. Android Studio开始同步依赖库
  2. 重新生成工程Build > Make Project

注意:不同版本的Android Studio(连同Gradle)所依赖的导航库不相同,如果遇到问题,查看使用 Safe Args 传递安全的数据以寻找解决方案。

在Android Studio Bumblebee | 2021.1.1 Patch 3中,gradle的脚本发生巨大变化。在新版本中,Safeargs的依赖将这样添加:

Gradle的Project部分,在plugins节添加

id 'androidx.navigation.safeargs.kotlin' version '2.5.0-alpha01' apply false

module部分在plugins节添加

id 'androidx.navigation.safeargs'

不同版本的Gradle在navigation插件版本不相同。

创建导航动作的参数

  1. 打开导航视图,点击FirstFragment,查看其属性。
  2. Actions栏中可以看到导航至SecondFragment
  3. 同理,查看SecondFragment的属性栏
  4. 点击Arguments "+"符号
  5. 弹出的对话框中,添加参数myArg,类型为整型Integer

FirstFragment添加代码,向SecondFragment发数据

初始应用中,点击FirstFragment的Next/Random按钮将跳转到第二个页面,但没有传递数据。在本步骤中将获取当前TextView中显示的数字并传输至SecondFragment。

  1. 打开FirstFragment.kt源代码文件
  2. 找到onViewCreated()方法,该方法在onCreateView方法之后被调用,可以实现组件的初始化。找到Random按钮的响应代码,注释掉原先的事件处理代码
  3. 实例化TextView,获取TextView中文本并转换为整数值
val showCountTextView = view.findViewById<TextView>(R.id.textview_first)
val currentCount = showCountTextView.text.toString().toInt()
  1. currentCount作为参数传递给actionFirstFragmentToSecondFragment()
val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment(currentCount)
  1. 添加导航事件代码
findNavController().navigate(action)

运行代码,点击FirstFragment的Count按钮,然后点击Random按钮,可以看到SecondFragment在头部的TextView已经显示正确的数字,但是屏幕中间还未出现随机数显示。

添加SecondFragment的代码

本节将更新SecondFragment.kt的代码,接受传递过来的整型参数并进行处理

  1. 导入navArgs包
import androidx.navigation.fragment.navArgs
  1. onViewCreated()代码之前添加一行
val args: SecondFragmentArgs by navArgs()
  1. onViewCreated()中获取传递过来的参数列表,提取count数值,并在textview_header中显示
val count = args.myArg
val countText = getString(R.string.random_heading, count)
view.findViewById<TextView>(R.id.textview_header).text = countText
  1. 根据count值生成随机数
val random = java.util.Random()
var randomNumber = 0
if (count > 0) {
   randomNumber = random.nextInt(count + 1)
}
  1. textview_random中显示count值
view.findViewById<TextView>(R.id.textview_random).text = randomNumber.toString()
  1. 运行应用程序,查看运行结果。

参考文献

  1. Build Your First Android App in Kotlin
  2. Navigation 组件使用入门
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,作为AI语言模型,我无法提供完整的安卓应用程序。下面是一个简单的示例,可用于开始编写新闻应用程序: 1. 在Android Studio中创建一个新项目,并选择Kotlin作为主要语言。 2. 在项目创建一个RecyclerView,用于显示新闻列表。 3. 创建一个新闻数据模型类,包括标题、描述、图片等信息。例如: ``` data class News(val title: String, val description: String, val image: Int) ``` 4. 创建一个新闻适配器类,用于将新闻数据绑定到RecyclerView中的项。例如: ``` class NewsAdapter(private val newsList: List<News>) : RecyclerView.Adapter<NewsAdapter.ViewHolder>() { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val titleTextView: TextView = view.findViewById(R.id.title_text_view) val descriptionTextView: TextView = view.findViewById(R.id.description_text_view) val imageView: ImageView = view.findViewById(R.id.image_view) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.news_item, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val news = newsList[position] holder.titleTextView.text = news.title holder.descriptionTextView.text = news.description holder.imageView.setImageResource(news.image) } override fun getItemCount() = newsList.size } ``` 5. 在MainActivity中初始化新闻数据,并将其传递给适配器。例如: ``` class MainActivity : AppCompatActivity() { private lateinit var newsRecyclerView: RecyclerView private lateinit var newsAdapter: NewsAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) newsRecyclerView = findViewById(R.id.news_recycler_view) newsAdapter = NewsAdapter(getNewsList()) newsRecyclerView.adapter = newsAdapter newsRecyclerView.layoutManager = LinearLayoutManager(this) } private fun getNewsList(): List<News> { return listOf( News("新闻标题1", "新闻描述1", R.drawable.news_image1), News("新闻标题2", "新闻描述2", R.drawable.news_image2), News("新闻标题3", "新闻描述3", R.drawable.news_image3), // 添加更多新闻... ) } } ``` 6. 在布局文件中添加RecyclerView和新闻项布局。例如: ``` <androidx.recyclerview.widget.RecyclerView android:id="@+id/news_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> <LinearLayout android:id="@+id/news_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerCrop"/> <TextView android:id="@+id/title_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold" android:padding="8dp"/> <TextView android:id="@+id/description_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:padding="8dp"/> </LinearLayout> ``` 这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值