這是 Android 開發(fā)(入門)課程 的第一部分《布局和交互》的第二次課程實踐哼鬓,導(dǎo)師是 Lyla Fujiwara音婶,主要內(nèi)容是變量練習(xí)和 Court Counter App竞慢。
變量練習(xí)
這節(jié)課通過代碼找茬來練習(xí)變量的使用骑冗,可總結(jié)出兩種類型的錯誤:編譯期錯誤和邏輯錯誤拙泽。
編譯期錯誤
Android Studio 能夠識別并字體標(biāo)紅窖张,右側(cè)紅色方塊指示錯誤位置,在聲明和初始化變量時常犯豹障。
聲明變量可理解為創(chuàng)建一個新變量冯事,如
int total;
初始化變量則為新變量設(shè)定一個初始值,如
total = 10;
通常習(xí)慣將聲明和初始化變量寫在一起血公,如
int total = 10;
這兩項操作有嚴(yán)格的格式規(guī)范:
數(shù)據(jù)類型 變量名 = 初始值;
數(shù)據(jù)類型應(yīng)與系統(tǒng)設(shè)定完全相同桅咆,如整型 int 不能是 Integer、integer 和 INT坞笙,字符串 String 首字母大寫岩饼。數(shù)據(jù)類型在 Android Studio 中默認(rèn)為藍(lán)色。
數(shù)據(jù)類型與變量名之間的空格不能省略薛夜,也不允許其他任何字符籍茧,如 _ 或 - 。
變量名應(yīng)遵循命名規(guī)則梯澜,可 Google 搜索 "variable names java" 找到 Oracle 的說明文檔 寞冯。通常變量名不能太長也不能短到一兩個字母;若是一個單詞則全小寫晚伙;若是多個單詞則用小駝峰命名法吮龄。變量名不能與數(shù)據(jù)類型相同,也不能有符號和空格咆疗。
-
初始值要與數(shù)據(jù)類型匹配漓帚,如字符串的值應(yīng)在雙引號內(nèi),不允許出現(xiàn)
int total = “10”;
分號結(jié)束午磁。
邏輯錯誤
非 XML 或 Java 語法錯誤尝抖,而是代碼功能無法實現(xiàn)的錯誤,所以 Android Studio 無法識別迅皇∶亮桑可關(guān)注以下幾點:
-
運(yùn)算符優(yōu)先級,可 Google 搜索 "arithmetic operators java" 找到 Oracle 的說明文檔 登颓。例如乘除的優(yōu)先級比加減的高搅荞,邏輯與的比邏輯或的高。若無法確定運(yùn)算符優(yōu)先級時用小括號分隔框咙,如
// 最先做加法咕痛,然后乘法,最后減法 total = 1 * ( 2 + 3 ) - 5;
變量僅在賦值時改變值扁耐,運(yùn)算不會暇检。
局部變量在 method 內(nèi)聲明产阱,只在 method 內(nèi)部有效婉称,在 Android Studio 中為黑色。
全局變量在 method 外聲明,在 method 之間有效王暗,可以保存數(shù)據(jù)悔据,在 Android Studio 中為紫色。
若變量不跨 method 使用時用局部變量即可俗壹。代碼按從上到下的順序運(yùn)行科汗,先前執(zhí)行過的代碼不會受后面的影響。
Court Counter App
首先構(gòu)建布局绷雏,按步驟進(jìn)行:分解 Views→畫 Views 層級圖→寫 XML 草稿→代碼實現(xiàn)头滔。
- 分解 Views。下圖為應(yīng)用最終布局圖涎显。
這里用到了嵌套ViewGroups坤检,有兩對水平對稱的 TextView 和三個 Button,每對垂直排列期吓,通過 vertical 的 LinearLayout 實現(xiàn)早歇;中間有一個 View 呈垂直線條狀,三者用 horizontal 的 LinearLayout 能實現(xiàn)讨勤;底部居中一個 Button箭跳,因此根 Views 應(yīng)為 RelativeLayout。
- 畫 Views 層級圖潭千,即樹狀圖
- 寫XML草稿谱姓,清晰條理
<RelativeLayout...>
<LinearLayout...>
<LinearLayout...>
<TextView... />
<TextView... />
<Button.../>
<Button.../>
<Button.../>
</LinearLayout>
<View... />
<LinearLayout...>
<TextView... />
<TextView... />
<Button... />
<Button... />
<Button.../>
</LinearLayout>
</LinearLayout>
<Button... />
</RelativeLayout>
- 代碼實現(xiàn)
In activity_main.xml
<RelativeLayout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:context="com.example.android.courtcouter.MainActivity">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:gravity="center_horizontal"
android:padding="16dp"
android:text="Team A"
android:textColor="#616161"
android:textSize="14sp" />
<TextView
android:id="@+id/team_a_score"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:paddingBottom="24dp"
android:text="0"
android:textColor="#000000"
android:textSize="56sp" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addThreeForTeamA"
android:text="+3 Points" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addTwoForTeamA"
android:text="+2 Points" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addOneForTeamA"
android:text="Free Throw" />
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:background="@android:color/darker_gray" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:gravity="center_horizontal"
android:padding="16dp"
android:text="Team B"
android:textColor="#616161"
android:textSize="14sp" />
<TextView
android:id="@+id/team_b_score"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:paddingBottom="24dp"
android:text="0"
android:textColor="#000000"
android:textSize="56sp" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addThreeForTeamB"
android:text="+3 Points" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addTwoForTeamB"
android:text="+2 Points" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:onClick="addOneForTeamB"
android:text="Free Throw" />
</LinearLayout>
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="22dp"
android:layout_marginRight="22dp"
android:onClick="resetScore"
android:text="reset" />
</RelativeLayout>
- 寫完代碼后可在 activity_main.xml 文件的 Design 標(biāo)簽下的 component Tree 驗證嵌套 ViewGroups 層次是否正確。
- TextView 中的文字使用了 gravity 屬性實現(xiàn)居中對齊刨晴,這種方式使得在 LinearLayout 中實現(xiàn)類似 RelativeLayout 中的對齊布局逝段。TextView 的邊界較大時效果更明顯。
- 兩個第二層 LinearLayout 使用了 layout_weight 屬性實現(xiàn)水平平分寬度割捅,注意此時雙方的初始寬度應(yīng)為 0dp奶躯,否則不為零的一方將多占一部分寬度。
- 中間的垂直線條可用寬度為 1dp 的 Views 來實現(xiàn)亿驾。
- 注意內(nèi)邊距 padding 與外邊距 margin 的區(qū)別嘹黔。padding 會使 Views 內(nèi)的內(nèi)容距離指定位置有間隔,而 margin 會使子 Views 距離父 Views 中的指定位置有間隔莫瞬,不會改變子 Views儡蔓。
styles.xml 文件能控制 App 的基本樣式,統(tǒng)一修改布局疼邀。文件在左側(cè) Project 標(biāo)簽 Android 視圖中 app→res→values 路徑下喂江。以下代碼將 Court Counter App 的主色調(diào)改為橙色。
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="colorPrimary">#FF9800</item>
<item name="android:colorButtonNormal">#FF9800</item>
</style>
</resources>
最后通過 Button 的 android:onClick 屬性連接 XML 與 Java旁振,在 Java 中通過 method 實現(xiàn)功能获询。
In MainActivity.java
package com.example.android.courtcouter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
int scoreTeamA = 0, scoreTeamB = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* Increase the score for Team A by 3 points.
*/
public void addThreeForTeamA(View view) {
scoreTeamA = scoreTeamA + 3;
displayForTeamA(scoreTeamA);
}
/**
* Increase the score for Team A by 2 points.
*/
public void addTwoForTeamA(View view) {
scoreTeamA = scoreTeamA + 2;
displayForTeamA(scoreTeamA);
}
/**
* Increase the score for Team A by 1 points.
*/
public void addOneForTeamA(View view) {
scoreTeamA = scoreTeamA + 1;
displayForTeamA(scoreTeamA);
}
/**
* Increase the score for Team B by 3 points.
*/
public void addThreeForTeamB(View view) {
scoreTeamB = scoreTeamB + 3;
displayForTeamB(scoreTeamB);
}
/**
* Increase the score for Team B by 2 points.
*/
public void addTwoForTeamB(View view) {
scoreTeamB = scoreTeamB + 2;
displayForTeamB(scoreTeamB);
}
/**
* Increase the score for Team B by 1 points.
*/
public void addOneForTeamB(View view) {
scoreTeamB = scoreTeamB + 1;
displayForTeamB(scoreTeamB);
}
/**
* Increase the score for Team B by 1 points.
*/
public void resetScore(View view) {
scoreTeamA = 0;
scoreTeamB = 0;
displayForTeamA(0);
displayForTeamB(0);
}
/**
* Displays the given score for Team A.
*/
public void displayForTeamA(int score) {
TextView scoreView = (TextView) findViewById(R.id.team_a_score);
scoreView.setText(String.valueOf(score));
}
/**
* Displays the given score for Team B.
*/
public void displayForTeamB(int score) {
TextView scoreView = (TextView) findViewById(R.id.team_b_score);
scoreView.setText(String.valueOf(score));
}
}
- 用全局變量保存兩隊的總分涨岁。
- 打開 "Add unambiguous imports on the fly" 功能,在發(fā)現(xiàn)未知量時立即添加清晰的 imports吉嚣,通常導(dǎo)入 Java 的庫或包梢薪。
- 在 Android Studio 中變量名默認(rèn)為紫色。
- 養(yǎng)成寫注釋的習(xí)慣尝哆。
課程至此秉撇,我做了第二個實戰(zhàn)項目——計分器應(yīng)用。這同樣是個簡單練習(xí)秋泄,在 Court Counter App 的基礎(chǔ)上稍作修改琐馆,達(dá)到如下圖的效果。
這次項目提交上去由導(dǎo)師審閱后恒序,給出了關(guān)于 App 資源文件相關(guān)的優(yōu)化建議啡捶,如
- 將 sp & dp 等尺寸相關(guān)的聲明放入 dimens.xml 內(nèi),而不是將 Views 的高度和寬度奸焙,以及字體的大小硬編碼 (hard coding)瞎暑;
- 將字符串變量放入了 strings.xml 內(nèi),方便應(yīng)用內(nèi)多處引用与帆,在翻譯應(yīng)用時也可以大大減少工作量了赌。
- 將 color 顏色值放入 colors.xml 內(nèi),統(tǒng)一管理顏色資源玄糟,而不是對顏色硬編碼勿她;
- 將樣式重復(fù)的 TextView、Button阵翎、LinearLayout 在 styles.xml 封裝調(diào)用逢并,使 XML 代碼簡潔易讀。
對 Android App 資源文件的介紹會在以后的課程中出現(xiàn)郭卫,在此先有個概念砍聊,不多作解釋。