Jetpack-Navigation

Navigation

“导航” 页面切换(处理导航图所需的一切,包括页面的跳转、参数的传递、动画效果的设置,以及Appbar的设置等)

NavHost是个容器,也是个控制器

Fragment

NavController

NavGraph

简单页面切换 完整例子:

  1. 新建各Empty Activity,起名MainActivity

  2. 新建两个Blank类型的Fragment,布局加个按钮用来点击跳转

  3. 新建Android Resource File,类型Navigation,起名nav

    点击New Destination按钮,添加前面创建的fragment布局,拖动进行关联(会有action,action有唯一id)

    此时的nav布局文件缺少HOST

  4. activity_main.xml移除掉内容,添加NavHostFragment,关联上前面创建的nav.xml,这样nav.xml中就有HOST了

  5. fragment中在onActivityCreate函数中添加控件的点击事件。点击事件中要关联上前面nav.xml的action

    1
    2
    3
    4
    5
    view!!.findViewById<Button>(R.id.button).setOnClickListener{
    val navController: NavController = Navigation.finNavController(it)
    //其中的actionId可以换成第二个页面的id,但推荐使用actionId
    navController.navigate(R.id.action_homeFragment_to_defaultFragment)
    }

MainActivity.kt

1
2
3
4
5
6
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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=".MainActivity">

<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav" />

</androidx.constraintlayout.widget.ConstraintLayout>

HomeFragment.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class HomeFragment extends Fragment {


public HomeFragment() {
// Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false);
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getView().findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavController controller = Navigation.findNavController(v);
//其中的actionId可以换成第二个页面的id(即nav.xml中第二个页面的id为defaultFragment),但推荐使用actionId
controller.navigate(R.id.action_homeFragment_to_defaultFragment);
}
});
}
}

fragment_home.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".HomeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="161dp"
tools:layout_editor_absoluteY="428dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

nav.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/my_nav_gragh"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.ab.navigationdemo.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_homeFragment_to_defaultFragment"
app:destination="@id/defaultFragment" />
</fragment>
<fragment
android:id="@+id/defaultFragment"
android:name="com.ab.navigationdemo.DefaultFragment"
android:label="fragment_default"
tools:layout="@layout/fragment_default" >
<action
android:id="@+id/action_defaultFragment_to_homeFragment"
app:destination="@id/homeFragment" />
</fragment>
</navigation>

页面切换并传递数据

方式1:用argument 传递简单的,静态的数据

  1. nav.xml中在接收数据的defaultFragment中,选中defaultFragment在右侧点击Arguments旁边的“+”,在弹窗中添加Name为name、Type为String、Default Value为Jack
  2. nav.xml中选中action的线,在右侧的Argument Default Values中添加默认值“Tome”
  3. 在页面跳转的时候会自动带过去(记得此时页面跳转用的是actionId,即controller.navigate(actionId)

方式2:用Bundle传递动态数据

  1. 在要传递的页面中HomeFragment.javaonActivityCreated中添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    getView().findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    EditText editText = getView().findViewById(R.id.editText);
    String str = editText.getText().toString();
    if (TextUtils.isEmpty(str)){
    Toast.makeText(getActivity(), "请输入名字!", Toast.LENGTH_SHORT).show();
    }
    Bundle bundle = new Bundle();
    //放进的是key-value
    bundle.putString("myName", str);
    NavController controller = Navigation.findNavController(v);
    //第一个参数是actionId,第二个参数是Bundle里面带有要传递过去的内容
    controller.navigate(R.id.action_homeFragment_to_defaultFragment, bundle);
    }
    });
  2. 接收的DefaultFragment.javaonActivityCreated

    1
    2
    //getString中是key
    String str = getArguments().getString("myName");

心算应用

包含:ViewModel、Screen Orientation 横竖屏切换、LiveData、Localization 资源国际适配、DataBinding、Vector Drawable、ViewModelSavedState、Navigation、补间动画

app/build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.ab.calculationtest"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
dataBinding.enabled = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.3.0-alpha07'
}

数据管理

MyViewModel.java数据管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.SavedStateHandle;
import java.util.Random;
/**
* @author shenbh
* time 2020/9/25 15:37
* AndroidViewModel可以访问全局的SharedPreference
* 维护者
*/
public class MyViewModel extends AndroidViewModel {
SavedStateHandle handle;
private static final String KEY_HIGH_SCORE = "key_high_score";
private static final String KEY_CURRENT_SCORE = "key_current_score";
private static final String KEY_LEFT_NUMBER = "key_left_number";
private static final String KEY_RIGHT_NUMBER = "key_right_number";
private static final String KEY_OPERATE = "key_operate";
private static final String KEY_ANSWER = "key_answer";
private static final String SAVE_SHP_DATA_NAME = "save_shp_data_name";
public boolean win_flag = false;
public MyViewModel(@NonNull Application application, SavedStateHandle handle) {
super(application);
if (!handle.contains(KEY_HIGH_SCORE)) {
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE);
handle.set(KEY_HIGH_SCORE, 0);
handle.set(KEY_CURRENT_SCORE, 0);
handle.set(KEY_LEFT_NUMBER, 0);
handle.set(KEY_RIGHT_NUMBER, 0);
handle.set(KEY_OPERATE, "+");
handle.set(KEY_ANSWER, 0);
}
this.handle = handle;
}

public MutableLiveData<Integer> getLeftNumber() {
return handle.getLiveData(KEY_LEFT_NUMBER);
}

public MutableLiveData<Integer> getRightNumber() {
return handle.getLiveData(KEY_RIGHT_NUMBER);
}
public MutableLiveData<String> getOperator() {
return handle.getLiveData(KEY_OPERATE);
}

public MutableLiveData<Integer> getAnswer() {
return handle.getLiveData(KEY_ANSWER);
}

public MutableLiveData<Integer> getHighScore() {
return handle.getLiveData(KEY_HIGH_SCORE);
}

public MutableLiveData<Integer> getCurrentScore() {
return handle.getLiveData(KEY_CURRENT_SCORE);
}

public void generator() {
int LEVEL = 20;
Random random = new Random();
int x, y;
x = random.nextInt(LEVEL) + 1;
y = random.nextInt(LEVEL) + 1;
if (x % 2 == 0) {
getOperator().setValue("+");
if (x > y) {
getAnswer().setValue(x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x - y);
} else {
getAnswer().setValue(y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y - x);
}
} else {
getOperator().setValue("-");
if (x > y){
getAnswer().setValue(x - y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y);
} else {
getAnswer().setValue(y - x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x);
}
}
}

@SuppressWarnings("ConstantConditions")
public void save(){
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shp.edit();
editor.putInt(KEY_HIGH_SCORE, getHighScore().getValue());
editor.apply();
}

@SuppressWarnings("ConstantConditions")
public void answerCorrect(){
getCurrentScore().setValue(getCurrentScore().getValue() + 1);
if (getCurrentScore().getValue() > getHighScore().getValue()) {
getHighScore().setValue(getCurrentScore().getValue());
win_flag = true;
}
generator();
}
}

欢迎页面

MainActivity.java加载多个fragment的容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundleimport androidx.appcompat.app.AlertDialog
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.navigation.ui.NavigationUI

class MainActivity : AppCompatActivity() {
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navController = Navigation.findNavController(this, R.id.fragment)
//setupActionBarWithNavController和onSupportNavigateUp设置页面上方标题取的是nav的每个fragment的标题内容。不设置则默认显示应用名称且没有向左的箭头
//但是MainActivity的布局不是nav的,所以显示的标题依然是应用名称
NavigationUI.setupActionBarWithNavController(this, navController)
}

/**
* 设置标题左上角的向左箭头的功能
*/
override fun onSupportNavigateUp(): Boolean {
if (navController.currentDestination!!.id == R.id.questionFragment){
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setTitle(getString(R.string.quit_dialog_title))
builder.setPositiveButton(getString(R.string.dialog_positive_message), { builder, which -> navController.navigateUp()})
builder.setNegativeButton(R.string.dialog_nagative_message, {builder, which -> {}})
val dialog: AlertDialog = builder.create()
dialog.show()
} else if (navController.currentDestination!!.id == R.id.titleFragment){
//在titleFragment的时候点击返回即退出应用
finish()
} else {
navController.navigate(R.id.titleFragment)
}
return super.onSupportNavigateUp()
}

/**
* 重写系统的返回键功能
*/
override fun onBackPressed() {
onSupportNavigateUp()
}
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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=".MainActivity">
<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav" />
</androidx.constraintlayout.widget.ConstraintLayout>

nav.xml自动加载第一个TitleFragment,即自动显示第一个TitleFragment而不会显示activity_main.xml内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.SavedStateViewModelFactory;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ab.calculationtest.databinding.FragmentTitleBinding;
import com.ab.calculationtest.viewmodel.MyViewModel;

public class TitleFragment extends Fragment {
public TitleFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_title, container, false);
MyViewModel myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(), requireActivity())).get(MyViewModel.class);
FragmentTitleBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_title, container, false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavController navController = Navigation.findNavController(v);
navController.navigate(R.id.action_titleFragment_to_questionFragment);
}
});
return binding.getRoot();
}
}

fragment_title.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="data"
type="com.ab.calculationtest.viewmodel.MyViewModel" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TitleFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.9" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_message"
android:textSize="@dimen/big_font"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.155" />

<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/coverage"
android:contentDescription="@string/title_image_info"
app:layout_constraintBottom_toTopOf="@+id/guideline17"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/guideline16" />

<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/title_button_message"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.836" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/high_score_message(data.highScore)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.966"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.066"
tools:text="@string/high_score_message" />

<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.26" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.7" />
</androidx.constraintlayout.widget.ConstraintLayout></layout>

路由管理

nav.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="utf-8"?>
<navigation
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/nav"
app:startDestination="@id/titleFragment">
<!--其中label设置每个fragment头部的标题-->
<fragment
android:id="@+id/titleFragment"
android:name="com.ab.calculationtest.TitleFragment"
android:label="@string/title_nav_message"
tools:layout="@layout/fragment_title" >
<!--action:关联fragment的动作-->
<action
android:id="@+id/action_titleFragment_to_questionFragment"
app:destination="@id/questionFragment"
app:enterAnim="@anim/slide_from_left" />
</fragment>
<fragment
android:id="@+id/questionFragment"
android:name="com.ab.calculationtest.QuestionFragment"
android:label="@string/question_nav_message"
tools:layout="@layout/fragment_question" >
<action
android:id="@+id/action_questionFragment_to_winFragment"
app:destination="@id/winFragment"
app:enterAnim="@anim/slide_from_left" />
<action
android:id="@+id/action_questionFragment_to_loseFragment"
app:destination="@id/loseFragment"
app:enterAnim="@anim/slide_from_left" />
</fragment>
<fragment
android:id="@+id/winFragment"
android:name="com.ab.calculationtest.WinFragment"
android:label="@string/win_nav_message"
tools:layout="@layout/fragment_win" >
<action
android:id="@+id/action_winFragment_to_titleFragment"
app:destination="@id/titleFragment" />
</fragment>
<fragment
android:id="@+id/loseFragment"
android:name="com.ab.calculationtest.LoseFragment"
android:label="@string/lose_nav_message"
tools:layout="@layout/fragment_lose" >
<action
android:id="@+id/action_loseFragment_to_titleFragment"
app:destination="@id/titleFragment" />
</fragment>
</navigation>

其中的补间动画

slide_from_left.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--"-100%:屏幕不可见";“0%:屏幕中间”;duration:持续时间-->
<translate
android:fromXDelta="-100%"
android:toXDelta="0%"
android:duration="1000"/>
</set>

答题页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.ab.calculationtest;

import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.SavedStateViewModelFactory;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.ab.calculationtest.databinding.FragmentQuestionBinding;
import com.ab.calculationtest.viewmodel.MyViewModel;

public class QuestionFragment extends Fragment {
public QuestionFragment() {
// Required empty public constructor
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_question, container, false);
//ViewModel初始化
final MyViewModel myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(), requireActivity())).get(MyViewModel.class);
myViewModel.generator();

//确保每次进来数据都重新开始
myViewModel.getCurrentScore().setValue(0);
final FragmentQuestionBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_question, container, false);
//databinding与viewModel进行绑定
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
final StringBuilder builder = new StringBuilder();
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button0:
builder.append("0");
break;
case R.id.button1:
builder.append("1");
break;
case R.id.button2:
builder.append("2");
break;
case R.id.button3:
builder.append("3");
break;
case R.id.button4:
builder.append("4");
break;
case R.id.button5:
builder.append("5");
break;
case R.id.button6:
builder.append("6");
break;
case R.id.button7:
builder.append("7");
break;
case R.id.button8:
builder.append("8");
break;
case R.id.button9:
builder.append("9");
break;
case R.id.clear:
//clear事件
//两种方式重置builder
builder.setLength(0);
// builder = new StringBuilder();
break;
default:
break;
}

if (builder.length() == 0){
binding.textView9.setText(getString(R.string.input_indicator));
} else {
binding.textView9.setText(builder.toString());
}
}
};

//给控件添加点击事件
binding.button0.setOnClickListener(listener);
binding.button1.setOnClickListener(listener);
binding.button2.setOnClickListener(listener);
binding.button3.setOnClickListener(listener);
binding.button4.setOnClickListener(listener);
binding.button5.setOnClickListener(listener);
binding.button6.setOnClickListener(listener);
binding.button7.setOnClickListener(listener);
binding.button8.setOnClickListener(listener);
binding.button9.setOnClickListener(listener);
binding.clear.setOnClickListener(listener);

//提交按钮的点击事件
binding.submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String answer = binding.textView9.getText().toString().trim();
if (answer.equals(getString(R.string.input_indicator)) || answer.equals(getString(R.string.answer_correct_message))){
Toast.makeText(requireActivity(), "请输入你的答案", Toast.LENGTH_SHORT).show();
return;
}
if (Integer.valueOf(builder.toString()).intValue() == myViewModel.getAnswer().getValue()){
myViewModel.answerCorrect();
builder.setLength(0);
binding.textView9.setText(R.string.answer_correct_message);
// builder.append(getString(R.string.answer_correct_message));
} else {
NavController navController = Navigation.findNavController(v);
if (myViewModel.win_flag){
navController.navigate(R.id.action_questionFragment_to_winFragment);
myViewModel.win_flag = false;
myViewModel.save();
} else {
navController.navigate(R.id.action_questionFragment_to_loseFragment);
}
}
}
});
return binding.getRoot();
}
}

fragment_question.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<!--使用databinding管理控件的数据以及事件-->
<data>
<variable
name="data"
type="com.ab.calculationtest.viewmodel.MyViewModel"
/>
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/frameLayout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".QuestionFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.4" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.4" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.6" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.7" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.9" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/current_score(safeUnbox(data.currentScore))}"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
tools:text="@string/current_score"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(safeUnbox(data.leftNumber))}"
android:textSize="@dimen/huge_font"
app:layout_constraintBottom_toBottomOf="@+id/textView5"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.115"
tools:text="@string/question_left_number"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/textView5"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.operator}"
tools:text="@string/question_operator"
android:textSize="@dimen/huge_font"
app:layout_constraintBottom_toBottomOf="@+id/textView6"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.101"
app:layout_constraintStart_toEndOf="@+id/textView4"
app:layout_constraintTop_toTopOf="@+id/textView6"
app:layout_constraintVertical_bias="0.0" />

<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:text="@{String.valueOf(safeUnbox(data.rightNumber))}"
android:textSize="@dimen/huge_font"
tools:text="@string/question_right_number"
app:layout_constraintBottom_toBottomOf="@+id/textView7"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.132"
app:layout_constraintStart_toEndOf="@+id/textView5"
app:layout_constraintTop_toTopOf="@+id/textView7"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/question_equal"
android:textSize="@dimen/huge_font"
app:layout_constraintBottom_toBottomOf="@+id/textView8"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.217"
app:layout_constraintStart_toEndOf="@+id/textView6"
app:layout_constraintTop_toTopOf="@+id/textView8"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/question_mark"
android:textSize="@dimen/huge_font"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.377"
app:layout_constraintStart_toEndOf="@+id/textView7"
app:layout_constraintTop_toTopOf="@+id/guideline3"
app:layout_constraintVertical_bias="0.428" />
<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/input_indicator"
android:textSize="@dimen/mid_font"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button1"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toTopOf="@+id/guideline11"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/guideline7" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button2"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button1"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
app:layout_constraintTop_toTopOf="@+id/button1" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button3"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button2"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
app:layout_constraintTop_toTopOf="@+id/button2" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button6"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button5"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button5"
app:layout_constraintTop_toTopOf="@+id/button5" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button4"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toTopOf="@+id/guideline12"
app:layout_constraintEnd_toStartOf="@+id/button5"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/guideline11"
app:layout_constraintVertical_bias="0.461" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button5"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button4"
app:layout_constraintEnd_toStartOf="@+id/button6"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button4"
app:layout_constraintTop_toTopOf="@+id/button4" />
<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button7"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toTopOf="@+id/guideline13"
app:layout_constraintEnd_toStartOf="@+id/button8"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/guideline12" />
<Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button8"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button7"
app:layout_constraintEnd_toStartOf="@+id/button9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button7"
app:layout_constraintTop_toTopOf="@+id/button7" />
<Button
android:id="@+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button9"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button8"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button8"
app:layout_constraintTop_toTopOf="@+id/button8" />
<Button
android:id="@+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clear"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toStartOf="@+id/button0"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/guideline8"
app:layout_constraintTop_toTopOf="@+id/guideline13" />
<Button
android:id="@+id/button0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button0"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/clear"
app:layout_constraintEnd_toStartOf="@+id/submit"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/clear"
app:layout_constraintTop_toTopOf="@+id/clear" />
<Button
android:id="@+id/submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit"
android:textSize="@dimen/button_font"
app:layout_constraintBottom_toBottomOf="@+id/button0"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button0"
app:layout_constraintTop_toTopOf="@+id/button0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

dimens.xml尺寸

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="huge_font">60sp</dimen>
<dimen name="big_font">40sp</dimen>
<dimen name="mid_font">30sp</dimen>
<dimen name="button_font">20sp</dimen>
<dimen name="land_btn_width">80dp</dimen>
</resources>

胜利页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import android.os.Bundle;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.SavedStateViewModelFactory;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ab.calculationtest.databinding.FragmentWinBinding;
import com.ab.calculationtest.viewmodel.MyViewModel;
public class WinFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_win, container, false);
MyViewModel myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(), requireActivity())).get(MyViewModel.class);
FragmentWinBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_win, container, false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button14.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavController navController = Navigation.findNavController(v);
navController.navigate(R.id.action_winFragment_to_titleFragment);
}
});
return binding.getRoot();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="data"
type="com.ab.calculationtest.viewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WinFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.45" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/win_image_message"
android:src="@drawable/ic_baseline_sentiment_satisfied_24"
app:layout_constraintBottom_toTopOf="@+id/guideline15"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline14" />
<TextView
android:id="@+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/win_message"
android:textSize="@dimen/big_font"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2"
app:layout_constraintVertical_bias="0.1" />
<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/win_score_message(data.highScore)}"
tools:text="@string/win_score_message"
android:textSize="@dimen/big_font"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline15"
app:layout_constraintVertical_bias="0.3" />
<Button
android:id="@+id/button14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_back_to_title"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline15" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

失败页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import android.os.Bundle;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.SavedStateViewModelFactory;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ab.calculationtest.databinding.FragmentLoseBinding;
import com.ab.calculationtest.viewmodel.MyViewModel;
public class LoseFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_lose, container, false);
MyViewModel myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(), requireActivity())).get(MyViewModel.class);
FragmentLoseBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_lose, container, false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button14.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavController navController = Navigation.findNavController(v);
navController.navigate(R.id.action_loseFragment_to_titleFragment);
}
});
return binding.getRoot();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="data"
type="com.ab.calculationtest.viewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/frameLayout3"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoseFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.45" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/lose_image_message"
android:src="@drawable/ic_baseline_sentiment_dissatisfied_24"
app:layout_constraintBottom_toTopOf="@+id/guideline15"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline14" />
<TextView
android:id="@+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lose_message"
android:textSize="@dimen/big_font"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2"
app:layout_constraintVertical_bias="0.1" />
<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/lose_score_message(data.currentScore)}"
tools:text="@string/lose_score_message"
android:textSize="@dimen/big_font"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline15"
app:layout_constraintVertical_bias="0.3" />
<Button
android:id="@+id/button14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_back_to_title"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline15" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

资源国际化

values/strings.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<resources>   
<string name="app_name">CalculationTest</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="title_message">Calculation Test</string>
<string name="title_image_info">title Image</string>
<string name="title_button_message">ENTER</string>
<string name="high_score_message">High Score:%d</string>
<string name="button1" translatable="false">1</string>
<string name="button2" translatable="false">2</string>
<string name="button3" translatable="false">3</string>
<string name="button4" translatable="false">4</string>
<string name="button5" translatable="false">5</string>
<string name="button6" translatable="false">6</string>
<string name="button7" translatable="false">7</string>
<string name="button8" translatable="false">8</string>
<string name="button9" translatable="false">9</string>
<string name="button0" translatable="false">0</string>
<string name="clear">C</string>
<string name="submit">OK</string>
<string name="question_equal" translatable="false">=</string>
<string name="question_mark" translatable="false">\?</string>
<string name="question_left_number" translatable="false">8</string>
<string name="question_operator" translatable="false">+</string>
<string name="question_right_number" translatable="false">9</string>
<string name="current_score">Score:%d</string>
<string name="input_indicator">Your Answer</string>
<string name="lose_image_message">lose image</string>
<string name="win_image_message">win image</string>
<string name="lose_message">You lose!</string>
<string name="win_message">You win!</string>
<string name="lose_score_message">Your Score:%d</string>
<string name="win_score_message">New Record:%d</string>
<string name="button_back_to_title">Back</string>
<string name="answer_correct_message">Correct go on</string>
<string name="quit_dialog_title">Ensure to Quit</string>
<string name="dialog_positive_message">OK</string>
<string name="dialog_nagative_message">CANCLE</string>
<string name="title_nav_message">Welcome</string>
<string name="question_nav_message">Test</string>
<string name="win_nav_message">win</string>
<string name="lose_nav_message">lose</string>
</resources>

values-zh-rCN/strings.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--资源国际化-->
<string name="app_name">心算应用</string>
<string name="clear">清除</string>
<string name="submit">提交</string>
<string name="current_score">得分:%d</string>
<string name="input_indicator">你的答案</string>
<string name="lose_image_message">失败图片</string>
<string name="win_image_message">成功图片</string>
<string name="lose_message">失败!</string>
<string name="win_message">成功!</string>
<string name="lose_score_message">你的得分:%d</string>
<string name="win_score_message">新纪录:%d</string>
<string name="button_back_to_title">返回</string>
<string name="answer_correct_message">回答正确,请继续</string>
<string name="quit_dialog_title">确认退出</string>
<string name="dialog_positive_message">好的</string>
<string name="dialog_nagative_message">取消</string>
<string name="hello_blank_fragment">欢迎</string>
<string name="high_score_message">最高记录:%d</string>
<string name="title_button_message">进入</string>
<string name="title_message">心算</string>
<string name="title_image_info">心算图</string>
<string name="title_nav_message">欢迎</string>
<string name="question_nav_message">测试</string>
<string name="win_nav_message">胜利</string>
<string name="lose_nav_message">失败</string>
</resources>