Button元素TextView。Drawable资源并将它们用作Button元素的背景。项目地址:https://github.com/google-developer-training/android-fundamentals-apps-v2/tree/master/Scorekeeper
创建项目

修改布局
<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="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.example.android.scorekeeper.MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="@string/team_1" />
<ImageButton
android:id="@+id/decreaseTeam1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_minus"
android:contentDescription=
"@string/minus_button_description" />
<TextView
android:id="@+id/score_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/initial_count" />
<ImageButton
android:id="@+id/increaseTeam1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_plus"
android:contentDescription=
"@string/plus_button_description" />
RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="@string/team_2" />
<ImageButton
android:id="@+id/decreaseTeam2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_minus"
android:contentDescription=
"@string/minus_button_description" />
<TextView
android:id="@+id/score_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/initial_count" />
<ImageButton
android:id="@+id/increaseTeam2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_plus"
android:contentDescription=
"@string/plus_button_description" />
RelativeLayout>
LinearLayout>

初始化TextView和得分计数变量
package com.dingjiaxiong.scorekeeper;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private int mScore1;
private int mScore2;
private TextView mScoreText1;
private TextView mScoreText2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScoreText1 = (TextView)findViewById(R.id.score_1);
mScoreText2 = (TextView)findViewById(R.id.score_2);
}
}
实现 ImageButton 元素的点击处理程序

一共四个
逻辑代码
public void decreaseScore(View view) {
int viewID = view.getId();
switch (viewID) {
// If it was on Team 1
case R.id.decreaseTeam1:
//Decrement the score and update the TextView
mScore1--;
mScoreText1.setText(String.valueOf(mScore1));
break;
// If it was Team 2
case R.id.decreaseTeam2:
// Decrement the score and update the TextView
mScore2--;
mScoreText2.setText(String.valueOf(mScore2));
}
}
public void increaseScore(View view) {
int viewID = view.getId();
switch (viewID) {
// If it was on Team 1
case R.id.increaseTeam1:
// Increment the score and update the TextView
mScore1++;
mScoreText1.setText(String.valueOf(mScore1));
break;
// If it was Team 2
case R.id.increaseTeam2:
// Increment the score and update the TextView
mScore2++;
mScoreText2.setText(String.valueOf(mScore2));
}
}
运行程序

创建一个ShapeDrawable
ShapeDrawable是在 XML 文件中由许多属性定义的原始几何形状,包括颜色、形状、填充等。它定义了一个矢量图形,可以放大和缩小而不会丢失任何定义。
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke
android:width="2dp"
android:color="@color/colorPrimary"/>
shape>

应用ShapeDrawable作为背景
四个图片按钮

修改组件宽度,现在按钮太小了


创建按钮样式
在 Android 中,样式可以继承其他样式的属性。您可以使用可选parent参数为您的样式声明父级,并具有以下属性:
styles.xml
<resources>
<style name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
- "colorPrimary"
>@color/colorPrimary
- "colorPrimaryDark"
>@color/colorPrimaryDark
- "colorAccent">@color/colorAccent
style>
<style name="ScoreButtons" parent="AppTheme">
- "android:background"
>@drawable/button_background
style>
<style name="PlusButtons" parent="ScoreButtons">
- "android:src"
>@drawable/ic_plus
- "android:contentDescription"
>@string/plus_button_description
style>
<style name="MinusButtons" parent="ScoreButtons">
- "android:src"
>@drawable/ic_minus
- "android:contentDescription"
>@string/minus_button_description
style>
<style name="ScoreText">
- "android:textAppearance"
>@style/TextAppearance.AppCompat.Headline
style>
resources>
布局文件
<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="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="@string/team_1"
style="@style/ScoreText" />
<ImageButton
android:id="@+id/decreaseTeam1"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
style="@style/MinusButtons"
android:onClick="decreaseScore"/>
<TextView
android:id="@+id/score_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/initial_count"
style="@style/ScoreText" />
<ImageButton
android:id="@+id/increaseTeam1"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
style="@style/PlusButtons"
android:onClick="increaseScore"/>
RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="@string/team_2"
style="@style/ScoreText" />
<ImageButton
android:id="@+id/decreaseTeam2"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
style="@style/MinusButtons"
android:onClick="decreaseScore"/>
<TextView
android:id="@+id/score_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/initial_count"
style="@style/ScoreText" />
<ImageButton
android:id="@+id/increaseTeam2"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
style="@style/PlusButtons"
android:onClick="increaseScore"/>
RelativeLayout>
LinearLayout>

更新样式
styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
- "colorPrimary"
>@color/colorPrimary
- "colorPrimaryDark"
>@color/colorPrimaryDark
- "colorAccent">@color/colorAccent
style>
<style name="ScoreButtons" parent="Widget.AppCompat.Button">
- "android:background"
>@drawable/button_background
- "android:tint"
>@color/colorPrimary
style>
<style name="PlusButtons" parent="ScoreButtons">
- "android:src"
>@drawable/ic_plus
- "android:contentDescription"
>
@string/plus_button_description
style>
<style name="MinusButtons" parent="ScoreButtons">
- "android:src"
>@drawable/ic_minus
- "android:contentDescription"
>
@string/minus_button_description
style>
<style name="ScoreText">
- "android:textAppearance"
>
@style/TextAppearance.AppCompat.Display3
style>
<style name="TeamText">
- "android:textAppearance"
>
@style/TextAppearance.AppCompat.Display1
style>
resources>
运行程序

仅对文件style.xml进行调整,所有视图都会更新以反映更改。
探索主题

改AppTheme

将主题按钮添加到菜单
添加字符资源
<string name="night_mode">Night Modestring>
<string name="day_mode">Day Modestring>
创建menu文件夹


<item
android:id="@+id/night_mode"
android:title="@string/night_mode"/>


运行程序

配置从菜单更改主题
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
// Change the label of the menu based on the state of the app.
int nightMode = AppCompatDelegate.getDefaultNightMode();
if(nightMode == AppCompatDelegate.MODE_NIGHT_YES){
menu.findItem(R.id.night_mode).setTitle(R.string.day_mode);
} else{
menu.findItem(R.id.night_mode).setTitle(R.string.night_mode);
}
return true;
}
/**
* Handles options menu item clicks.
*
* @param item The item that was pressed
* @return returns true since the item click wa handled
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Check if the correct item was clicked.
if (item.getItemId() == R.id.night_mode) {
// Get the night mode state of the app.
int nightMode = AppCompatDelegate.getDefaultNightMode();
// Set the theme mode for the restarted activity.
if (nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode
(AppCompatDelegate.MODE_NIGHT_NO);
} else {
AppCompatDelegate.setDefaultNightMode
(AppCompatDelegate.MODE_NIGHT_YES);
}
// Recreate the activity for the theme change to take effect.
recreate();
}
return true;
}
保存Activity状态
当前MainActivity.java完整代码
package com.dingjiaxiong.scorekeeper;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Member variables for holding the score
private int mScore1;
private int mScore2;
// Member variables for the two score TextView elements
private TextView mScoreText1;
private TextView mScoreText2;
// Tags to be used as the keys in OnSavedInstanceState
static final String STATE_SCORE_1 = "Team 1 Score";
static final String STATE_SCORE_2 = "Team 2 Score";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Find the TextViews by ID
mScoreText1 = findViewById(R.id.score_1);
mScoreText2 = findViewById(R.id.score_2);
// Restores the scores if there is savedInstanceState.
if (savedInstanceState != null) {
mScore1 = savedInstanceState.getInt(STATE_SCORE_1);
mScore2 = savedInstanceState.getInt(STATE_SCORE_2);
//Set the score text views
mScoreText1.setText(String.valueOf(mScore1));
mScoreText2.setText(String.valueOf(mScore2));
}
}
/**
* Handles the onClick of both the decrement buttons.
*
* @param view The button view that was clicked
*/
public void decreaseScore(View view) {
// Get the ID of the button that was clicked.
int viewID = view.getId();
switch (viewID) {
// If it was on Team 1:
case R.id.decreaseTeam1:
// Decrement the score and update the TextView.
mScore1--;
mScoreText1.setText(String.valueOf(mScore1));
break;
// If it was Team 2:
case R.id.decreaseTeam2:
// Decrement the score and update the TextView.
mScore2--;
mScoreText2.setText(String.valueOf(mScore2));
}
}
/**
* Handles the onClick of both the increment buttons.
*
* @param view The button view that was clicked
*/
public void increaseScore(View view) {
// Get the ID of the button that was clicked.
int viewID = view.getId();
switch (viewID) {
// If it was on Team 1:
case R.id.increaseTeam1:
// Increment the score and update the TextView.
mScore1++;
mScoreText1.setText(String.valueOf(mScore1));
break;
// If it was Team 2:
case R.id.increaseTeam2:
// Increment the score and update the TextView.
mScore2++;
mScoreText2.setText(String.valueOf(mScore2));
}
}
/**
* Creates the night mode menu option.
*
* @param menu The menu in the action bar
* @return True to display the menu, false to hide it
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
// Change the label of the menu based on the state of the app.
int nightMode = AppCompatDelegate.getDefaultNightMode();
if(nightMode == AppCompatDelegate.MODE_NIGHT_YES){
menu.findItem(R.id.night_mode).setTitle(R.string.day_mode);
} else{
menu.findItem(R.id.night_mode).setTitle(R.string.night_mode);
}
return true;
}
/**
* Handles options menu item clicks.
*
* @param item The item that was pressed
* @return returns true since the item click wa handled
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Check if the correct item was clicked.
if (item.getItemId() == R.id.night_mode) {
// Get the night mode state of the app.
int nightMode = AppCompatDelegate.getDefaultNightMode();
// Set the theme mode for the restarted activity.
if (nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode
(AppCompatDelegate.MODE_NIGHT_NO);
} else {
AppCompatDelegate.setDefaultNightMode
(AppCompatDelegate.MODE_NIGHT_YES);
}
// Recreate the activity for the theme change to take effect.
recreate();
}
return true;
}
/**
* Method that is called when the configuration changes,
* used to preserve the state of the app.
*
* @param outState The bundle that will be passed in to the Activity when it is restored.
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
// Save the scores.
outState.putInt(STATE_SCORE_1, mScore1);
outState.putInt(STATE_SCORE_2, mScore2);
super.onSaveInstanceState(outState);
}
}
运行程序

Drawable元素增强了应用程序 UI 的外观。ShapeDrawable是在 XML 文件中定义的原始几何形状。定义 a 的属性ShapeDrawable包括颜色、形状、填充等。style可以指定常见的属性,例如高度、填充、字体颜色、字体大小和背景颜色。style不应包含与布局相关的信息。style可以应用于View、Activity或整个应用程序。style应用于一个或整个应用程序的AActivity必须在AndroidManifest.xml文件中定义。parentXML 中的属性。style应用于活动或整个应用程序中的元素集合时View,这称为主题。android:theme属性。