背景

1. 本学期接触到了安卓开发的课程,预计使用一个半月的时间带领剩下3个没有开发经验的同学开发好一个像样的app
2. 自己本人也有了解的兴趣。

概述

下面将从构建新项目开始,逐步实现一些小功能,快速地认识一些基本的操作。于此同时,我也会和angular的知识进行对比叙述。

构建新项目

打开android studio 左上角 File -> new
红色框布局主要是 XML+setContentView
蓝色框是 Jetpack Compose (近几年google推荐的)
image.png
本文章介绍的是XML+setContentView项目,选型原因主要是社区完善,且布局设计对新手友好,上手较快。

文件结构

记得将左上角的模式调成project模式
在这个java下的包是我们的控制类
image.png

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
       // 绑定v层
        setContentView(R.layout.activity_main)
     }
}

从上到下是图片资源的存放文件夹,可以看到很多drawable前缀的文件夹,代表着不同分辨率下用到的图片
layout文件夹放着页面和组件文件,menu文件夹放着导航的项目(接下来会重点介绍)
image.png
mipmap文件夹与图片资源同理,不过存放的是app的图标
values文件夹放的是一些常用变量
AndroidManifest.xml是注册页面的地方
image.png

渲染流程

image.png
AndroidManifest.xml
image.png
MainActivity控制类,注意这里引入一个新概念,对于src下的文件名也可以使用R去访问,R也可以去访问values文件夹中的变量。
image.png
有一个很方便的布局,在布局标签上声明androidx.constraintlayout.widget.ConstraintLayout就可以使用图形界面去快速的布局
这里有个学习链接(图形化布局)
image.png

实现导入组件库

image.png
找到这个文件,添加依赖image.png
点击File -> Sync Project With Gradle Files
在官网中,复制代码底部导航栏指导
activity_main.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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="421dp"
        android:layout_height="93dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/bottom_navigation_menu" />

</androidx.constraintlayout.widget.ConstraintLayout>

接下来创建一个文件夹menu,注意这里比较特殊,这里需要创建特定的文件夹,否则无法识别到到其他文件中, 且menu,item控件都会识别不了。
image.png
选择type为menu
截图 2026-03-12 12-26-52.png
接下来将内容填进去,发现爆红了,之前我们说过了可以用R去访问资源,那么在v层中就是使用@去访问静态资源。当然动态生成的就在c层进行绑定。
截图 2026-03-11 17-43-26.png
填加资源
截图 2026-03-11 17-45-38.png
我们可以使用官方的图标
截图 2026-03-11 18-00-14.png
image.png
image.png
最后静态导航栏的实现效果
image.png

实现一个可滑动的横向列表

这里就可以进一步探索,动态渲染的机制,在angular中我们经常在模板中使用@for去循环构造模板,在android中怎么实现呢。
在activity_main.xml中加入这段代码

  <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewHorizontal"
        android:layout_width="426dp"
        android:layout_height="75dp"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.533"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

在layout中创建子项目的模板文件item_horizontal.xml
截图 2026-03-11 18-29-11.png

<?xml version="1.0" encoding="utf-8"?>
<TextView  android:id="@+id/textView"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:textSize="16sp"
    android:layout_margin="8dp"/>

接下来我们创建适配器,用于处理循环渲染的步骤。

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.R

class HorizontalAdapter(private val dataList: List<String>) :
    RecyclerView.Adapter<HorizontalAdapter.ViewHolder>() {

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(itemView.id)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // LayoutInflater.from(parent.context)将转化xml为对象
        // inflat函数开始进行创建循环中的子项目, 第一个参数获取子项目的样式,第二个参数获取父盒子的样式,第三个参数表示是否构造完一个个就塞到父盒子里
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_horizontal, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = dataList[position]
        holder.textView.text = item
        // 可以设置点击事件
        holder.itemView.setOnClickListener {
            // 处理点击
        }
    }

    override fun getItemCount() = dataList.size
}

然后去使用了该循环的xml文件,对应的c层注册该适配器
截图 2026-03-11 18-31-44.png
效果,可滑动
image.png

实现页面跳转

我们点击导航栏应该让页面作出一些变化,但是导航栏不能整体变化,我们就会想到angular的组件思想。那么,在android中如何实现呢?我们接下来会使用到Fragment。
创建Fragment
截图 2026-03-11 19-02-36.png
image.png
同理创建homeFragment
接下来将我们之前写在activity_main.xml的部分控件放到homeFragment.xml中

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

    <TextView
        android:id="@+id/textView"
        android:layout_width="209dp"
        android:layout_height="52dp"
        android:layout_marginBottom="84dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@+id/btnMaterial"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.549"
        app:layout_constraintStart_toStartOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewHorizontal"
        android:layout_width="426dp"
        android:layout_height="75dp"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.533"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnMaterial"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="120dp"
        android:text="我是一个 Material 按钮"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.612" />

</androidx.constraintlayout.widget.ConstraintLayout>

同理控制器中的逻辑也需要迁移过去

package com.example.myapplication

import HorizontalAdapter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class HomeFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // 1. 加载布局文件
        val view = inflater.inflate(R.layout.fragment_home, container, false)

        // 2. 从当前 Fragment 的视图中查找 RecyclerView
        val recyclerView: RecyclerView = view.findViewById(R.id.recyclerViewHorizontal)

        // 3. 设置水平布局管理器
        val layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
        recyclerView.layoutManager = layoutManager

        // 4. 准备数据
        val data = mutableListOf<String>()
        for (i in 1..20) {
            data.add("Item $i")
        }

        // 5. 设置适配器(确保 HorizontalAdapter 已定义)
        val adapter = HorizontalAdapter(data)
        recyclerView.adapter = adapter

        // 6. 返回填充好的视图
        return view
    }
}

对于MainActivity我们需要让他去选择需要显示的Fragment

package com.example.myapplication

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)

        // 设置默认显示的 Fragment(例如首页)
        if (savedInstanceState == null) {
            replaceFragment(HomeFragment())
        }

        // 设置导航项选中监听
        bottomNav.setOnNavigationItemSelectedListener { item ->
            when (item.itemId) {
                R.id.page_1 -> {  // 注意这里的 ID 必须与菜单文件中一致
                    replaceFragment(HomeFragment())
                    true
                }
                R.id.page_2 -> {
                    replaceFragment(PersonalFragment())
                    true
                }
                else -> false
            }
        }
    }
    // 替换 Fragment 的辅助方法
    private fun replaceFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, fragment)
            .commit()
    }
}

接下来点击运行,点击导航栏就完成页面跳转效果了。

表单提交

表格

交验器

状态管理

自定义样式

总结

  1. android的布局很有意思用xml文件编写,还可以使用图形化进行布局,十分好上手。
  2. 对于静态资源的访问,用R去访问,v层用@文件夹/资源名去访问。
  3. 基本是c层用控件id对v层的控件属性进行操作
  4. 像常用的for循环,menu等控件,android都有特定的创建模式,规范较强。
  5. Fragment相当于组件
  6. 以上写法耦合性太强

标签: none

添加新评论