# Android Programming - Lecture 1 ###### tags: `Kotlin Programming` ## Android 專案介紹 ### 組織方式 通常習慣以 Android 方式瀏覽專案。  ### 專案結構  * manifests:存放 Android APP 的主要設定檔。 * java:存放專案主要 kotlin 程式碼。 * res:存放專案不是程式碼的資源檔案,例如:Layout、圖片、文字等。 ### Android Application Components * Activities:處理 UI 介面的程式,我們課程著重在這邊。 * Services:處理背景處理執行的程式。 * Broadcast Receivers:處理 Android OS 和 APP 之間的溝通的程式。 * Content Providers:管理資料,可提供給其他 APP 的程式。 參考:https://www.tutorialspoint.com/android/android_application_components.htm #### AndroidManifest.xml 每個 Android APP 都會有此檔案,存放 APP 的基本資訊(icon、label等)、有哪些 Activity、Service、需要使用到的權限等。 ```xml= <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloworld"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.HelloWorld"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <!--表示可從手機系統桌面圖示啟動--> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ``` 參考:https://developer.android.com/guide/topics/manifest/manifest-intro #### MainActivity.kt 寫 UI 的 Android APP 一開始會執行的地方,一開始只有 `onCreate()` 方法,載入對應的 Layout。 ```kotlin= package com.example.helloworld import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 這邊載入了 activity_main 的 Layout } } ``` ##### Lifecycle  來源:https://developer.android.com/guide/components/activities/activity-lifecycle #### activity_main.xml MainActivity 的介面 Layout 檔案,可透過圖形化介面編輯器或是直接編輯 XML 方式操作。  1. 調色盤:可拉取需要的元件到 UI 上。 2. 元件樹:顯示元件之間的結構。 3. 設計編輯器:分別在設計和藍圖視角編輯 Layout。 4. 屬性:可以修改你選擇的元件的屬性。 5. 觀看模式:可切換使用圖形化介面或 XML 編輯等。 ##### Layout 簡介 * LinearLayout:以縱向或橫向呈現。 * RelativeLayout:以相對位置呈現。 * FrameLayout:只顯示單一元件,所有元件都在左上角疊在一起。 * TableLayout:以表格方式呈現。 * ConstraintLayout:RelativeLayout 的延伸,透過物件自已本身與其它物件之間的約束來決定它的位置。 ## Draw Playing Cards App 接著讓我們開啟一個新專案做一個抽撲克牌的小遊戲。 ### 建立專案 1. Create New Project。  2. Template 選擇 Empty Activity。  3. 命名為 Draw Playing Cards,語言選擇 kotlin ,Minimum SDK 選擇 Android 11.0。  ### 新增按鈕 1. 切換至 activity_main.xml,並使用 XML 編輯模式。  2. 將內容修改成: 也可以不直接編輯 XML 使用圖形化編輯介面新增這些元件與設定屬性。 ```xml= <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_vertical" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="1" android:textSize="30sp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Draw" /> </LinearLayout> ``` 這邊我們使用 LinearLayout,並且放置 TextView 與 Button 兩個元件。 其中設定 LinearLayout 屬性為: * `android:layout_width="match_parent"`:`match_parent`會依照上層的大小填滿上層物件,所以元件在畫面中的寬度會被撐滿。 * `android:layout_height="wrap_content"`:`wrap_content`會依照內容物件的大小去做改變,所以元件的高只吃它使用的範圍。 * `android:layout_gravity="center_vertical"`:設定為置中對齊。 * `android:orientation="vertical"`:設定為垂直排版。 可以在圖形化編輯介面選則 Linear Layout 設定屬性並預覽效果看看。  Linear Layout 參考:https://developer.android.com/guide/topics/ui/layout/linear 3. 檢視設計介面。  4. 打開模擬器預覽。  ### 綁定按鈕 #### 使用 View Binding(推薦) 1. 使用 View Binding 前必須先在 `build.gradle` 中設定 `viewBinding` 爲 `true`。 ``` android { ... buildFeatures { viewBinding true } } ``` 2. 在 Button 的 Layout 中新增 `android:id="@+id/draw_button"`。 id 的格式為 `@+id/你想要取得名字`。 ```xml= <Button android:id="@+id/draw_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Draw" /> ``` 3. 在 MainActivity.kt 中對按鈕進行綁定及操作。 MainActivity.kt: ```kotlin= package com.example.drawplayingcards import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.drawplayingcards.databinding.ActivityMainBinding private lateinit var binding: ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.drawButton.text = "Let's Draw" } } ``` 4. 可看到 `onCreate()` 時確實有把原本按鈕在 Layout 上設定的 `DRAW` 改為剛剛寫的 `Let's Draw`。  參考:https://developer.android.com/topic/libraries/view-binding#activities #### 使用 findViewById 1. 在 Button 的 Layout 中新增 `android:id="@+id/draw_button"`。 id 的格式為 `@+id/你想取的名字`。 ```xml= <Button android:id="@+id/draw_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Draw" /> ``` 2. 在 MainActivity.kt 中對按鈕進行綁定及操作。 請用輸入的,才會自動提示並 import 需要的元件。 ```kotlin= val drawButton: Button = findViewById(R.id.draw_button) drawButton.text = "Let's Draw" ``` MainActivity.kt: ```kotlin= package com.example.drawplayingcards import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // -------------------這裡開始------------------- val drawButton: Button = findViewById(R.id.draw_button) drawButton.text = "Let's Draw" // -------------------這裡結束------------------- } } ``` 3. 可看到 `onCreate()` 時確實有把原本按鈕在 Layout 上設定的 `DRAW` 改為剛剛寫的 `Let's Draw`。  ### 點擊事件 1. 在 MainActivity.kt 中對按鈕設定`OnClickListener`,並使用 Toast 顯示訊息。 ```kotlin= binding.drawButton.setOnClickListener { Toast.makeText(this, "button clicked", Toast.LENGTH_SHORT).show() } ``` Toast 元件參考:https://developer.android.com/guide/topics/ui/notifiers/toasts MainActivity.kt: ```kotlin= package com.example.drawplayingcards import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import com.example.drawplayingcards.databinding.ActivityMainBinding private lateinit var binding: ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // -------------------這裡開始------------------- binding.drawButton.setOnClickListener { Toast.makeText(this, "button clicked", Toast.LENGTH_SHORT).show() } // -------------------這裡結束------------------- } } ``` 2. 可看到當點擊按鈕時,跳出 Toast 並顯示 `button clicked` 訊息。  ### 點擊並改變 TextView 1. 在 TextView 的 Layout 中新增 `android:id="@+id/result_text"`。 ```xml= <TextView android:id="@+id/result_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="1" android:textSize="30sp" /> ``` 2. 在 MainActivity.kt 中撰寫對應程式。 * 監聽按鈕 `click` 時執行 `darwCard()` Function: ```kotlin= binding.drawButton.setOnClickListener { darwCard() } ``` * 新增 `darwCard()` 方法:取得亂數、綁定 `TextView` 並更改上面的文字。 ```kotlin= private fun drawCard() { val randomInt = Random().nextInt(13) + 1 binding.resultText.text = randomInt.toString() } ``` MainActivity.kt: ```kotlin= package com.example.drawplayingcards import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.drawplayingcards.databinding.ActivityMainBinding import java.util.* private lateinit var binding: ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // -------------------這裡開始------------------- binding.drawButton.setOnClickListener { drawCard() } // -------------------這裡結束------------------- } // -------------------這裡開始------------------- private fun drawCard() { val randomInt = Random().nextInt(13) + 1 binding.resultText.text = randomInt.toString() } // -------------------這裡結束------------------- } ``` 3. 點擊 DRAW 按鈕時上面 `TextView` 隨機跳出 `1~13` 的數字。  ### 新增撲克牌圖檔 1. 下載 https://drive.google.com/file/d/1-Yx9dQgtEq8nsq5-DGWU9payrv6jNAft/view?usp=sharing 並解壓縮圖檔。 2. 拖曳檔案新增至 `res/drawable` 內。  3. 檢視圖檔。  ### 使用 ImageView 元件 我們將以 `ImageView` 取代剛剛的 `TextView`。 1. 在 Layout 中移除原本的 `TextView` 並新增 `ImageView`。 ```xml= <ImageView android:id="@+id/playing_card_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/spade_empty" /> ``` activity_main.xml: ```xml= <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_vertical" android:orientation="vertical" tools:context=".MainActivity"> > <ImageView android:id="@+id/playing_card_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/spade_empty" /> <Button android:id="@+id/draw_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Draw" /> </LinearLayout> ``` 2. 在 MainActivity.kt 中撰寫對應程式。 修改 `drawCard()` Function,綁定 `ImageView` 並依不同的 `randomInt` 設定不同的撲克牌圖片。 ```kotlin= private fun drawCard() { val drawableResource = when (Random().nextInt(10) + 1) { 1 -> R.drawable.spade_1 2 -> R.drawable.spade_2 3 -> R.drawable.spade_3 4 -> R.drawable.spade_4 5 -> R.drawable.spade_5 6 -> R.drawable.spade_6 7 -> R.drawable.spade_7 8 -> R.drawable.spade_8 9 -> R.drawable.spade_9 10 -> R.drawable.spade_10 else -> R.drawable.spade_empty } binding.playingCardImage.setImageResource(drawableResource) } ``` MainActivity.kt: ```kotlin= package com.example.drawplayingcards import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.drawplayingcards.databinding.ActivityMainBinding import java.util.* private lateinit var binding: ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.drawButton.setOnClickListener { drawCard() } } // -------------------這裡開始------------------- private fun drawCard() { val drawableResource = when (Random().nextInt(10) + 1) { 1 -> R.drawable.spade_1 2 -> R.drawable.spade_2 3 -> R.drawable.spade_3 4 -> R.drawable.spade_4 5 -> R.drawable.spade_5 6 -> R.drawable.spade_6 7 -> R.drawable.spade_7 8 -> R.drawable.spade_8 9 -> R.drawable.spade_9 10 -> R.drawable.spade_10 else -> R.drawable.spade_empty } binding.playingCardImage.setImageResource(drawableResource) } // -------------------這裡結束------------------- } ``` 3. 點擊 DRAW 按鈕時上面 `ImageView` 會隨機顯示 `1~10` 的撲克牌花樣。 
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.