经过一段时间观看视频进行Android的学习,将现今所学知识进行阶段性总结编写了一款口算测试App,并成功将其打包成apk在手机上运行。主要使用了LiveData,DataBinding,ViewModel以及Fragment等,话不多说,上代码。
一、界面的搭建
创建四个界面,分别为TitleFragment,QuestionFragment,WinFragment以及LoseFragment
因为使用了DataBinding和LiveData,要在build.gradle中添加依赖
dataBinding.enabled true
implementation ‘androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha02‘//最新的依赖可以在官网中找到
同时创建MyViewModel.java,继承自AndroidViewModel
1 package com.example.calculationtest; 2 3 import android.app.Application; 4 import android.content.Context; 5 import android.content.SharedPreferences; 6 7 import androidx.annotation.NonNull; 8 import androidx.lifecycle.AndroidViewModel; 9 import androidx.lifecycle.MutableLiveData; 10 import androidx.lifecycle.SavedStateHandle; 11 12 import java.util.Random; 13 14 public class MyViewModel extends AndroidViewModel { 15 private SavedStateHandle handle; 16 private static String KEY_HIGH_SCORE = "key_high_score"; 17 private static String KEY_LEFT_NUMBER = "key_left_number"; 18 private static String KEY_RIGHT_NUMBER = "key_right_number"; 19 private static String KEY_OPERATOR = "key_operator"; 20 private static String KEY_ANSWER = "key_answer"; 21 private static String SAVE_SHP_DATA_NAME = "save_shp_data_name"; 22 private static String KEY_CURRENT_SCORE = "key_current_score"; 23 boolean win_flag = false; 24 25 public MyViewModel(@NonNull Application application, SavedStateHandle handle) { 26 super(application); 27 if (!handle.contains(KEY_HIGH_SCORE)) { 28 SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE); 29 handle.set(KEY_HIGH_SCORE, shp.getInt(KEY_HIGH_SCORE, 0)); 30 handle.set(KEY_LEFT_NUMBER, 0); 31 handle.set(KEY_RIGHT_NUMBER, 0); 32 handle.set(KEY_OPERATOR, " "); 33 handle.set(KEY_ANSWER, 0); 34 handle.set(KEY_CURRENT_SCORE, 0); 35 } 36 this.handle = handle; 37 } 38 39 public MutableLiveData<Integer> getLeftNumber() { 40 return handle.getLiveData(KEY_LEFT_NUMBER); 41 } 42 43 public MutableLiveData<Integer> getRightNumber() { 44 return handle.getLiveData(KEY_RIGHT_NUMBER); 45 } 46 47 public MutableLiveData<String> getOpreator() { 48 return handle.getLiveData(KEY_OPERATOR); 49 } 50 51 public MutableLiveData<Integer> getHighScore() { 52 return handle.getLiveData(KEY_HIGH_SCORE); 53 } 54 55 public MutableLiveData<Integer> getCurrentScore() { 56 return handle.getLiveData(KEY_CURRENT_SCORE); 57 } 58 59 public MutableLiveData<Integer> getAnswer() { 60 return handle.getLiveData(KEY_ANSWER); 61 } 62 63 void generator() { 64 int LEVEL = 20; 65 Random random = new Random(); 66 int x, y; 67 x = random.nextInt(LEVEL) 1; 68 y = random.nextInt(LEVEL) 1; 69 if (x % 2 == 0) { 70 getOpreator().setValue(" "); 71 if (x > y) { 72 getAnswer().setValue(x); 73 getLeftNumber().setValue(y); 74 getRightNumber().setValue(x - y); 75 } else { 76 getAnswer().setValue(y); 77 getLeftNumber().setValue(x); 78 getRightNumber().setValue(y - x); 79 } 80 } else { 81 getOpreator().setValue("-"); 82 if (x > y) { 83 getAnswer().setValue(x - y); 84 getLeftNumber().setValue(x); 85 getRightNumber().setValue(y); 86 } else { 87 getAnswer().setValue(y - x); 88 getLeftNumber().setValue(y); 89 getRightNumber().setValue(x); 90 } 91 } 92 } 93 94 95 void save() { 96 SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE); 97 SharedPreferences.Editor editor = shp.edit(); 98 editor.putInt(KEY_HIGH_SCORE, getHighScore().getValue()); 99 editor.apply(); 100 } 101 102 103 void answerCorrect() { 104 getCurrentScore().setValue(getCurrentScore().getValue() 1); 105 if (getCurrentScore().getValue() > getHighScore().getValue()) { 106 getHighScore().setValue(getCurrentScore().getValue()); 107 win_flag = true; 108 } 109 generator(); 110 } 111 112 }
fragment_title.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools"> 5 6 <data> 7 <variable 8 name="data" 9 type="com.example.calculationtest.MyViewModel" /> 10 </data> 11 12 <androidx.constraintlayout.widget.ConstraintLayout 13 android:layout_width="match_parent" 14 android:layout_height="match_parent" 15 tools:context=".TitleFragment"> 16 17 <androidx.constraintlayout.widget.Guideline 18 android:id="@ id/guideline" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:orientation="vertical" 22 app:layout_constraintGuide_percent="0.1" /> 23 24 <androidx.constraintlayout.widget.Guideline 25 android:id="@ id/guideline2" 26 android:layout_width="wrap_content" 27 android:layout_height="wrap_content" 28 android:orientation="vertical" 29 app:layout_constraintGuide_percent="0.9" /> 30 31 <TextView 32 android:id="@ id/textView" 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content" 35 android:layout_marginStart="8dp" 36 android:layout_marginTop="8dp" 37 android:layout_marginEnd="8dp" 38 android:layout_marginBottom="8dp" 39 android:text="@string/title_message" 40 android:textAlignment="center" 41 android:textSize="@dimen/big_font" 42 app:layout_constraintBottom_toBottomOf="parent" 43 app:layout_constraintEnd_toStartOf="@ id/guideline2" 44 app:layout_constraintHorizontal_bias="0.652" 45 app:layout_constraintStart_toStartOf="@ id/guideline" 46 app:layout_constraintTop_toTopOf="parent" 47 app:layout_constraintVertical_bias="0.201" /> 48 49 <ImageView 50 android:id="@ id/imageView" 51 android:layout_width="0dp" 52 android:layout_height="0dp" 53 android:layout_marginStart="8dp" 54 android:layout_marginTop="8dp" 55 android:layout_marginEnd="8dp" 56 android:layout_marginBottom="8dp" 57 android:contentDescription="@string/title_image_info" 58 android:src="@drawable/titleimage" 59 app:layout_constraintBottom_toBottomOf="parent" 60 app:layout_constraintDimensionRatio="w,1:1" 61 app:layout_constraintEnd_toStartOf="@ id/guideline2" 62 app:layout_constraintStart_toStartOf="@ id/guideline" 63 app:layout_constraintTop_toTopOf="parent" /> 64 65 <Button 66 android:id="@ id/button" 67 android:layout_width="0dp" 68 android:layout_height="wrap_content" 69 android:layout_marginStart="8dp" 70 android:layout_marginTop="8dp" 71 android:layout_marginEnd="8dp" 72 android:layout_marginBottom="8dp" 73 android:text="@string/title_button_message" 74 app:layout_constraintBottom_toBottomOf="parent" 75 app:layout_constraintEnd_toEndOf="@ id/imageView" 76 app:layout_constraintHorizontal_bias="0.5" 77 app:layout_constraintStart_toStartOf="@ id/imageView" 78 app:layout_constraintTop_toTopOf="parent" 79 app:layout_constraintVertical_bias="0.85" /> 80 81 <TextView 82 android:id="@ id/textView2" 83 android:layout_width="wrap_content" 84 android:layout_height="wrap_content" 85 android:text="@{@string/high_score_message(data.highScore)}" 86 app:layout_constraintBottom_toBottomOf="parent" 87 app:layout_constraintEnd_toEndOf="parent" 88 app:layout_constraintHorizontal_bias="0.875" 89 app:layout_constraintStart_toStartOf="parent" 90 app:layout_constraintTop_toTopOf="parent" 91 app:layout_constraintVertical_bias="0.116" 92 tools:text="High Score:%d" /> 93 </androidx.constraintlayout.widget.ConstraintLayout> 94 </layout>
- imageview所用图片是网上下载的
- 右上角的"high score :%d",需要与viewmodel中的数据绑定
- 点击Enter,即可进入答题界面
TitleFragment.java
1 @Override 2 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 3 Bundle savedInstanceState) { 4 MyViewModel myViewModel; 5 myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity())).get(MyViewModel.class); 6 FragmentTitleBinding binding; 7 binding = DataBindingUtil.inflate(inflater,R.layout.fragment_title,container,false); 8 binding.setData(myViewModel); 9 binding.setLifecycleOwner(requireActivity()); 10 binding.button.setOnClickListener(new View.OnClickListener() { 11 @Override 12 public void onClick(View v) { 13 NavController controller = Navigation.findNavController(v); 14 controller.navigate(R.id.action_titleFragment_to_questionFragment); 15 } 16 }); 17 return binding.getRoot(); 18 // Inflate the layout for this fragment 19 //return inflater.inflate(R.layout.fragment_title, container, false); 20 }
fragment_question.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools"> 5 6 <data> 7 <variable 8 name="data" 9 type="com.example.calculationtest.MyViewModel" /> 10 </data> 11 12 <androidx.constraintlayout.widget.ConstraintLayout 13 android:layout_width="match_parent" 14 android:layout_height="match_parent" 15 tools:context=".QuestionFragment"> 16 17 <androidx.constraintlayout.widget.Guideline 18 android:id="@ id/guideline9" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:orientation="horizontal" 22 app:layout_constraintGuide_percent="0.85" /> 23 24 <androidx.constraintlayout.widget.Guideline 25 android:id="@ id/guideline8" 26 android:layout_width="wrap_content" 27 android:layout_height="wrap_content" 28 android:orientation="horizontal" 29 app:layout_constraintGuide_percent="0.45" /> 30 31 <androidx.constraintlayout.widget.Guideline 32 android:id="@ id/guideline7" 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content" 35 android:orientation="horizontal" 36 app:layout_constraintGuide_percent="0.37" /> 37 38 <androidx.constraintlayout.widget.Guideline 39 android:id="@ id/guideline3" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:orientation="vertical" 43 app:layout_constraintGuide_percent="0.1" /> 44 45 <androidx.constraintlayout.widget.Guideline 46 android:id="@ id/guideline4" 47 android:layout_width="wrap_content" 48 android:layout_height="wrap_content" 49 android:orientation="vertical" 50 app:layout_constraintGuide_percent="0.9" /> 51 52 <androidx.constraintlayout.widget.Guideline 53 android:id="@ id/guideline5" 54 android:layout_width="wrap_content" 55 android:layout_height="wrap_content" 56 android:orientation="horizontal" 57 app:layout_constraintGuide_percent="0.15" /> 58 59 <androidx.constraintlayout.widget.Guideline 60 android:id="@ id/guideline6" 61 android:layout_width="wrap_content" 62 android:layout_height="wrap_content" 63 android:orientation="horizontal" 64 app:layout_constraintGuide_percent="0.25" /> 65 66 <TextView 67 android:id="@ id/textView3" 68 android:layout_width="wrap_content" 69 android:layout_height="wrap_content" 70 android:layout_marginStart="8dp" 71 android:layout_marginTop="8dp" 72 android:layout_marginEnd="8dp" 73 android:layout_marginBottom="8dp" 74 android:text="@{@string/current_score(data.currentScore)}" 75 app:layout_constraintBottom_toTopOf="@ id/guideline5" 76 app:layout_constraintEnd_toEndOf="parent" 77 app:layout_constraintStart_toStartOf="parent" 78 app:layout_constraintTop_toTopOf="@ id/guideline5" 79 tools:text="Score:5" /> 80 81 <TextView 82 android:id="@ id/textView4" 83 android:layout_width="wrap_content" 84 android:layout_height="wrap_content" 85 android:text="@{String.valueOf(safeUnbox(data.leftNumber))}" 86 android:textSize="@dimen/huge_font" 87 app:layout_constraintBottom_toBottomOf="@ id/textView5" 88 app:layout_constraintEnd_toStartOf="@ id/textView5" 89 app:layout_constraintHorizontal_bias="0.5" 90 app:layout_constraintStart_toStartOf="@ id/guideline3" 91 app:layout_constraintTop_toTopOf="@ id/textView5" 92 tools:text="8" /> 93 94 <TextView 95 android:id="@ id/textView5" 96 android:layout_width="wrap_content" 97 android:layout_height="wrap_content" 98 android:text="@{data.opreator}" 99 android:textSize="@dimen/huge_font" 100 app:layout_constraintBottom_toBottomOf="@ id/textView6" 101 app:layout_constraintEnd_toStartOf="@ id/textView6" 102 app:layout_constraintHorizontal_bias="0.5" 103 app:layout_constraintStart_toEndOf="@ id/textView4" 104 app:layout_constraintTop_toTopOf="@ id/textView6" 105 tools:text=" " /> 106 107 <TextView 108 android:id="@ id/textView6" 109 android:layout_width="wrap_content" 110 android:layout_height="wrap_content" 111 android:text="@{String.valueOf(safeUnbox(data.rightNumber))}" 112 android:textSize="@dimen/huge_font" 113 app:layout_constraintBottom_toBottomOf="@ id/textView7" 114 app:layout_constraintEnd_toStartOf="@ id/textView7" 115 app:layout_constraintHorizontal_bias="0.5" 116 app:layout_constraintStart_toEndOf="@ id/textView5" 117 app:layout_constraintTop_toTopOf="@ id/textView7" 118 tools:text="9" /> 119 120 <TextView 121 android:id="@ id/textView7" 122 android:layout_width="wrap_content" 123 android:layout_height="wrap_content" 124 android:text="@string/equal_symbol" 125 android:textSize="@dimen/huge_font" 126 app:layout_constraintBottom_toBottomOf="@ id/textView8" 127 app:layout_constraintEnd_toStartOf="@ id/textView8" 128 app:layout_constraintHorizontal_bias="0.5" 129 app:layout_constraintStart_toEndOf="@ id/textView6" 130 app:layout_constraintTop_toTopOf="@ id/textView8" 131 tools:text="=" /> 132 133 <TextView 134 android:id="@ id/textView8" 135 android:layout_width="wrap_content" 136 android:layout_height="wrap_content" 137 android:text="@string/question_mark" 138 android:textSize="@dimen/huge_font" 139 app:layout_constraintBottom_toTopOf="@ id/guideline6" 140 app:layout_constraintEnd_toStartOf="@ id/guideline4" 141 app:layout_constraintHorizontal_bias="0.5" 142 app:layout_constraintStart_toEndOf="@ id/textView7" 143 app:layout_constraintTop_toTopOf="@ id/guideline6" 144 tools:text="?" /> 145 146 <TextView 147 android:id="@ id/textView9" 148 android:layout_width="wrap_content" 149 android:layout_height="wrap_content" 150 android:layout_marginStart="8dp" 151 android:layout_marginTop="8dp" 152 android:layout_marginEnd="8dp" 153 android:layout_marginBottom="8dp" 154 android:text="@string/input_indicator" 155 android:textSize="@dimen/mid_font" 156 app:layout_constraintBottom_toTopOf="@ id/guideline7" 157 app:layout_constraintEnd_toStartOf="@ id/guideline4" 158 app:layout_constraintStart_toStartOf="@ id/guideline3" 159 app:layout_constraintTop_toTopOf="@ id/guideline7" /> 160 161 <androidx.constraintlayout.widget.Guideline 162 android:id="@ id/guideline10" 163 android:layout_width="wrap_content" 164 android:layout_height="wrap_content" 165 android:orientation="horizontal" 166 app:layout_constraintGuide_percent="0.55" /> 167 168 <androidx.constraintlayout.widget.Guideline 169 android:id="@ id/guideline11" 170 android:layout_width="wrap_content" 171 android:layout_height="wrap_content" 172 android:orientation="horizontal" 173 app:layout_constraintGuide_percent="0.65" /> 174 175 <androidx.constraintlayout.widget.Guideline 176 android:id="@ id/guideline12" 177 android:layout_width="wrap_content" 178 android:layout_height="wrap_content" 179 android:orientation="horizontal" 180 app:layout_constraintGuide_percent="0.75" /> 181 182 <Button 183 android:id="@ id/button1" 184 android:layout_width="wrap_content" 185 android:layout_height="wrap_content" 186 android:text="@string/button1" 187 android:textSize="@dimen/button_font" 188 app:layout_constraintBottom_toTopOf="@ id/guideline10" 189 app:layout_constraintEnd_toStartOf="@ id/button2" 190 app:layout_constraintHorizontal_bias="0.5" 191 app:layout_constraintStart_toStartOf="@ id/guideline3" 192 app:layout_constraintTop_toTopOf="@ id/guideline8" /> 193 194 <Button 195 android:id="@ id/button2" 196 android:layout_width="wrap_content" 197 android:layout_height="wrap_content" 198 android:text="@string/button2" 199 android:textSize="@dimen/button_font" 200 app:layout_constraintBottom_toBottomOf="@ id/button1" 201 app:layout_constraintEnd_toStartOf="@ id/button3" 202 app:layout_constraintHorizontal_bias="0.5" 203 app:layout_constraintStart_toEndOf="@ id/button1" 204 app:layout_constraintTop_toTopOf="@ id/button1" /> 205 206 <Button 207 android:id="@ id/button3" 208 android:layout_width="wrap_content" 209 android:layout_height="wrap_content" 210 android:text="@string/button3" 211 android:textSize="@dimen/button_font" 212 app:layout_constraintBottom_toBottomOf="@ id/button2" 213 app:layout_constraintEnd_toStartOf="@ id/guideline4" 214 app:layout_constraintHorizontal_bias="0.5" 215 app:layout_constraintStart_toEndOf="@ id/button2" 216 app:layout_constraintTop_toTopOf="@ id/button2" /> 217 218 <Button 219 android:id="@ id/button4" 220 android:layout_width="wrap_content" 221 android:layout_height="wrap_content" 222 android:text="@string/button4" 223 android:textSize="@dimen/button_font" 224 app:layout_constraintBottom_toTopOf="@ id/guideline11" 225 app:layout_constraintEnd_toStartOf="@ id/button5" 226 app:layout_constraintHorizontal_bias="0.5" 227 app:layout_constraintStart_toStartOf="@ id/guideline3" 228 app:layout_constraintTop_toTopOf="@ id/guideline10" /> 229 230 <Button 231 android:id="@ id/button6" 232 android:layout_width="wrap_content" 233 android:layout_height="wrap_content" 234 android:text="@string/button6" 235 android:textSize="@dimen/button_font" 236 app:layout_constraintBottom_toBottomOf="@ id/button5" 237 app:layout_constraintEnd_toStartOf="@ id/guideline4" 238 app:layout_constraintHorizontal_bias="0.5" 239 app:layout_constraintStart_toEndOf="@ id/button5" 240 app:layout_constraintTop_toTopOf="@ id/button5" 241 app:layout_constraintVertical_bias="0.0" /> 242 243 <Button 244 android:id="@ id/button5" 245 android:layout_width="wrap_content" 246 android:layout_height="wrap_content" 247 android:text="@string/button5" 248 android:textSize="@dimen/button_font" 249 app:layout_constraintBottom_toBottomOf="@ id/button4" 250 app:layout_constraintEnd_toStartOf="@ id/button6" 251 app:layout_constraintHorizontal_bias="0.5" 252 app:layout_constraintStart_toEndOf="@ id/button4" 253 app:layout_constraintTop_toTopOf="@ id/button4" 254 app:layout_constraintVertical_bias="0.0" /> 255 256 <Button 257 android:id="@ id/button7" 258 android:layout_width="wrap_content" 259 android:layout_height="wrap_content" 260 android:text="@string/button7" 261 android:textSize="@dimen/button_font" 262 app:layout_constraintBottom_toTopOf="@ id/guideline12" 263 app:layout_constraintEnd_toStartOf="@ id/button8" 264 app:layout_constraintHorizontal_bias="0.5" 265 app:layout_constraintStart_toStartOf="@ id/guideline3" 266 app:layout_constraintTop_toTopOf="@ id/guideline11" /> 267 268 <Button 269 android:id="@ id/button8" 270 android:layout_width="wrap_content" 271 android:layout_height="wrap_content" 272 android:text="@string/button8" 273 android:textSize="@dimen/button_font" 274 app:layout_constraintBottom_toBottomOf="@ id/button7" 275 app:layout_constraintEnd_toStartOf="@ id/button9" 276 app:layout_constraintHorizontal_bias="0.5" 277 app:layout_constraintStart_toEndOf="@ id/button7" 278 app:layout_constraintTop_toTopOf="@ id/button7" /> 279 280 <Button 281 android:id="@ id/button9" 282 android:layout_width="wrap_content" 283 android:layout_height="wrap_content" 284 android:text="@string/button9" 285 android:textSize="@dimen/button_font" 286 app:layout_constraintBottom_toBottomOf="@ id/button8" 287 app:layout_constraintEnd_toStartOf="@ id/guideline4" 288 app:layout_constraintHorizontal_bias="0.5" 289 app:layout_constraintStart_toEndOf="@ id/button8" 290 app:layout_constraintTop_toTopOf="@ id/button8" /> 291 292 <Button 293 android:id="@ id/buttonClear" 294 android:layout_width="wrap_content" 295 android:layout_height="wrap_content" 296 android:text="@string/buttonClear" 297 android:textSize="@dimen/button_font" 298 app:layout_constraintBottom_toTopOf="@ id/guideline9" 299 app:layout_constraintEnd_toStartOf="@ id/button0" 300 app:layout_constraintHorizontal_bias="0.5" 301 app:layout_constraintStart_toStartOf="@ id/guideline3" 302 app:layout_constraintTop_toTopOf="@ id/guideline12" /> 303 304 <Button 305 android:id="@ id/button0" 306 android:layout_width="wrap_content" 307 android:layout_height="wrap_content" 308 android:text="@string/button0" 309 android:textSize="@dimen/button_font" 310 app:layout_constraintBottom_toBottomOf="@ id/buttonClear" 311 app:layout_constraintEnd_toStartOf="@ id/buttonSubmit" 312 app:layout_constraintHorizontal_bias="0.5" 313 app:layout_constraintStart_toEndOf="@ id/buttonClear" 314 app:layout_constraintTop_toTopOf="@ id/buttonClear" /> 315 316 <Button 317 android:id="@ id/buttonSubmit" 318 android:layout_width="wrap_content" 319 android:layout_height="wrap_content" 320 android:text="@string/buttonSubmit" 321 android:textSize="@dimen/button_font" 322 app:layout_constraintBottom_toBottomOf="@ id/button0" 323 app:layout_constraintEnd_toStartOf="@ id/guideline4" 324 app:layout_constraintHorizontal_bias="0.5" 325 app:layout_constraintStart_toEndOf="@ id/button0" 326 app:layout_constraintTop_toTopOf="@ id/button0" /> 327 328 </androidx.constraintlayout.widget.ConstraintLayout> 329 </layout>
QuestionFragment.java
设置按键监听
1 @Override 2 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 3 Bundle savedInstanceState) { 4 final MyViewModel myViewModel; 5 myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity())).get(MyViewModel.class); 6 myViewModel.generator(); 7 myViewModel.getCurrentScore().setValue(0); 8 final FragmentQuestionBinding binding; 9 binding = DataBindingUtil.inflate(inflater, R.layout.fragment_question, container, false); 10 binding.setData(myViewModel); 11 binding.setLifecycleOwner(requireActivity()); 12 final StringBuilder builder = new StringBuilder(); 13 View.OnClickListener listener = new View.OnClickListener() { 14 @Override 15 public void onClick(View v) { 16 switch (v.getId()) { 17 case R.id.button0: 18 builder.append("0"); 19 break; 20 case R.id.button1: 21 builder.append("1"); 22 break; 23 case R.id.button2: 24 builder.append("2"); 25 break; 26 case R.id.button3: 27 builder.append("3"); 28 break; 29 case R.id.button4: 30 builder.append("4"); 31 break; 32 case R.id.button5: 33 builder.append("5"); 34 break; 35 case R.id.button6: 36 builder.append("6"); 37 break; 38 case R.id.button7: 39 builder.append("7"); 40 break; 41 case R.id.button8: 42 builder.append("8"); 43 break; 44 case R.id.button9: 45 builder.append("9"); 46 break; 47 case R.id.buttonClear: 48 builder.setLength(0); 49 break; 50 } 51 if (builder.length() == 0) { 52 binding.textView9.setText(getString(R.string.input_indicator)); 53 } else { 54 binding.textView9.setText(builder.toString()); 55 } 56 } 57 }; 58 59 binding.button0.setOnClickListener(listener); 60 binding.button1.setOnClickListener(listener); 61 binding.button2.setOnClickListener(listener); 62 binding.button3.setOnClickListener(listener); 63 binding.button4.setOnClickListener(listener); 64 binding.button5.setOnClickListener(listener); 65 binding.button6.setOnClickListener(listener); 66 binding.button7.setOnClickListener(listener); 67 binding.button8.setOnClickListener(listener); 68 binding.button9.setOnClickListener(listener); 69 binding.buttonClear.setOnClickListener(listener); 70 71 binding.buttonSubmit.setOnClickListener(new View.OnClickListener() { 72 @Override 73 public void onClick(View v) { 74 if (builder.length() == 0) { 75 builder.append("-1"); 76 } 77 if (Integer.valueOf(builder.toString()).intValue() == myViewModel.getAnswer().getValue()) { 78 myViewModel.answerCorrect(); 79 builder.setLength(0); 80 binding.textView9.setText(R.string.answer_correct_message); 81 } else { 82 NavController controller = Navigation.findNavController(v); 83 if (myViewModel.win_flag) { 84 controller.navigate(R.id.action_questionFragment_to_winFragment); 85 myViewModel.win_flag = false; 86 myViewModel.save(); 87 } else { 88 controller.navigate(R.id.action_questionFragment_to_loseFragment); 89 } 90 } 91 } 92 }); 93 return binding.getRoot(); 94 // Inflate the layout for this fragment 95 //return inflater.inflate(R.layout.fragment_question, container, false); 96 }
fragment_win.xml
在创建drawable中创建矢量图
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools"> 5 6 <data> 7 <variable 8 name="data" 9 type="com.example.calculationtest.MyViewModel" /> 10 </data> 11 12 <androidx.constraintlayout.widget.ConstraintLayout 13 android:layout_width="match_parent" 14 android:layout_height="match_parent" 15 tools:context=".WinFragment"> 16 17 <androidx.constraintlayout.widget.Guideline 18 android:id="@ id/guideline15" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:orientation="horizontal" 22 app:layout_constraintGuide_percent="0.1" /> 23 24 <androidx.constraintlayout.widget.Guideline 25 android:id="@ id/guideline16" 26 android:layout_width="wrap_content" 27 android:layout_height="wrap_content" 28 android:orientation="horizontal" 29 app:layout_constraintGuide_percent="0.45" /> 30 31 <ImageView 32 android:id="@ id/imageView3" 33 android:layout_width="0dp" 34 android:layout_height="0dp" 35 android:layout_marginStart="8dp" 36 android:layout_marginTop="8dp" 37 android:layout_marginEnd="8dp" 38 android:layout_marginBottom="8dp" 39 android:contentDescription="@string/win_image_message" 40 android:src="@drawable/ic_sentiment_satisfied_black_24dp" 41 app:layout_constraintBottom_toTopOf="@ id/guideline16" 42 app:layout_constraintEnd_toEndOf="parent" 43 app:layout_constraintStart_toStartOf="parent" 44 app:layout_constraintTop_toTopOf="@ id/guideline15" /> 45 46 <TextView 47 android:id="@ id/textView12" 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:layout_marginStart="8dp" 51 android:layout_marginTop="8dp" 52 android:layout_marginEnd="8dp" 53 android:layout_marginBottom="8dp" 54 android:text="@string/win_message" 55 android:textSize="@dimen/big_font" 56 app:layout_constraintBottom_toBottomOf="parent" 57 app:layout_constraintEnd_toEndOf="parent" 58 app:layout_constraintStart_toStartOf="parent" 59 app:layout_constraintTop_toTopOf="@ id/guideline16" 60 app:layout_constraintVertical_bias="0.1" /> 61 62 <TextView 63 android:id="@ id/textView13" 64 android:layout_width="wrap_content" 65 android:layout_height="wrap_content" 66 android:layout_marginStart="8dp" 67 android:layout_marginTop="8dp" 68 android:layout_marginEnd="8dp" 69 android:layout_marginBottom="8dp" 70 android:text="@{@string/win_score_message(data.highScore)}" 71 android:textSize="@dimen/big_font" 72 app:layout_constraintBottom_toBottomOf="parent" 73 app:layout_constraintEnd_toEndOf="parent" 74 app:layout_constraintStart_toStartOf="parent" 75 app:layout_constraintTop_toBottomOf="@ id/imageView3" 76 app:layout_constraintVertical_bias="0.30" 77 tools:text="New Record:"/> 78 79 <Button 80 android:id="@ id/button11" 81 android:layout_width="wrap_content" 82 android:layout_height="wrap_content" 83 android:layout_marginStart="8dp" 84 android:layout_marginTop="8dp" 85 android:layout_marginEnd="8dp" 86 android:layout_marginBottom="8dp" 87 android:text="@string/button_back_to_title" 88 android:textSize="@dimen/button_font" 89 app:layout_constraintBottom_toBottomOf="parent" 90 app:layout_constraintEnd_toEndOf="parent" 91 app:layout_constraintStart_toStartOf="parent" 92 app:layout_constraintTop_toBottomOf="@ id/imageView3" 93 app:layout_constraintVertical_bias="0.55" /> 94 </androidx.constraintlayout.widget.ConstraintLayout> 95 </layout>
WinFragment.java
创建Back键返回初始界面监听
1 @Override 2 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 3 Bundle savedInstanceState) { 4 // Inflate the layout for this fragment 5 MyViewModel myViewModel = ViewModelProviders.of(requireActivity(),new SavedStateViewModelFactory(requireActivity())).get(MyViewModel.class); 6 FragmentWinBinding binding; 7 binding = DataBindingUtil.inflate(inflater,R.layout.fragment_win,container,false); 8 binding.setData(myViewModel); 9 binding.setLifecycleOwner(requireActivity()); 10 binding.button11.setOnClickListener(new View.OnClickListener() { 11 @Override 12 public void onClick(View v) { 13 Navigation.findNavController(v).navigate(R.id.action_winFragment_to_titleFragment); 14 } 15 }); 16 return binding.getRoot(); 17 //return inflater.inflate(R.layout.fragment_win, container, false); 18 }
fragment_lose.xml
同理先创建矢量图
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools"> 5 6 <data> 7 <variable 8 name="data" 9 type="com.example.calculationtest.MyViewModel" /> 10 </data> 11 12 <androidx.constraintlayout.widget.ConstraintLayout 13 android:layout_width="match_parent" 14 android:layout_height="match_parent" 15 tools:context=".LoseFragment"> 16 17 <androidx.constraintlayout.widget.Guideline 18 android:id="@ id/guideline13" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:orientation="horizontal" 22 app:layout_constraintGuide_percent="0.1" /> 23 24 <androidx.constraintlayout.widget.Guideline 25 android:id="@ id/guideline14" 26 android:layout_width="wrap_content" 27 android:layout_height="wrap_content" 28 android:orientation="horizontal" 29 app:layout_constraintGuide_percent="0.45" /> 30 31 <ImageView 32 android:id="@ id/imageView2" 33 android:layout_width="0dp" 34 android:layout_height="0dp" 35 android:layout_marginStart="8dp" 36 android:layout_marginTop="8dp" 37 android:layout_marginEnd="8dp" 38 android:layout_marginBottom="8dp" 39 android:contentDescription="@string/lose_image_message" 40 android:src="@drawable/ic_sentiment_dissatisfied_black_24dp" 41 app:layout_constraintBottom_toTopOf="@ id/guideline14" 42 app:layout_constraintEnd_toEndOf="parent" 43 app:layout_constraintStart_toStartOf="parent" 44 app:layout_constraintTop_toTopOf="@ id/guideline13" /> 45 46 <TextView 47 android:id="@ id/textView10" 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:layout_marginStart="8dp" 51 android:layout_marginTop="8dp" 52 android:layout_marginEnd="8dp" 53 android:layout_marginBottom="8dp" 54 android:text="@string/lose_message" 55 android:textSize="@dimen/big_font" 56 app:layout_constraintBottom_toBottomOf="parent" 57 app:layout_constraintEnd_toEndOf="parent" 58 app:layout_constraintHorizontal_bias="0.5" 59 app:layout_constraintStart_toStartOf="parent" 60 app:layout_constraintTop_toTopOf="@ id/guideline14" 61 app:layout_constraintVertical_bias="0.1" /> 62 63 <TextView 64 android:id="@ id/textView11" 65 android:layout_width="wrap_content" 66 android:layout_height="wrap_content" 67 android:layout_marginStart="8dp" 68 android:layout_marginTop="8dp" 69 android:layout_marginEnd="8dp" 70 android:layout_marginBottom="8dp" 71 android:text="@{@string/lose_score_message(data.currentScore)}" 72 android:textSize="@dimen/big_font" 73 app:layout_constraintBottom_toBottomOf="parent" 74 app:layout_constraintEnd_toEndOf="parent" 75 app:layout_constraintStart_toStartOf="parent" 76 app:layout_constraintTop_toTopOf="@ id/guideline14" 77 app:layout_constraintVertical_bias="0.30" 78 tools:text="Your Score:"/> 79 80 <Button 81 android:id="@ id/button10" 82 android:layout_width="wrap_content" 83 android:layout_height="wrap_content" 84 android:text="@string/button_back_to_title" 85 android:textSize="@dimen/button_font" 86 app:layout_constraintBottom_toBottomOf="parent" 87 app:layout_constraintEnd_toEndOf="parent" 88 app:layout_constraintHorizontal_bias="0.50" 89 app:layout_constraintStart_toStartOf="parent" 90 app:layout_constraintTop_toTopOf="@ id/guideline14" 91 app:layout_constraintVertical_bias="0.55" /> 92 </androidx.constraintlayout.widget.ConstraintLayout> 93 </layout>
LoseFragment.java
创建Back键返回初始界面监听
1 @Override 2 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 3 Bundle savedInstanceState) { 4 MyViewModel myViewModel = ViewModelProviders.of(requireActivity(),new SavedStateViewModelFactory(requireActivity())).get(MyViewModel.class); 5 FragmentLoseBinding binding; 6 binding = DataBindingUtil.inflate(inflater,R.layout.fragment_lose,container,false); 7 binding.setData(myViewModel); 8 binding.setLifecycleOwner(requireActivity()); 9 binding.button10.setOnClickListener(new View.OnClickListener() { 10 @Override 11 public void onClick(View v) { 12 Navigation.findNavController(v).navigate(R.id.action_loseFragment_to_titleFragment); 13 } 14 }); 15 return binding.getRoot(); 16 // Inflate the layout for this fragment 17 //return inflater.inflate(R.layout.fragment_lose, container, false); 18 }
二、确定页面之间跳转关系
1)创建navigation
2)导入fargment
三、导航栏返回键建立以及返回键的拦截
MainActivity.java
1 package com.example.calculationtest; 2 3 import androidx.appcompat.app.AlertDialog; 4 import androidx.appcompat.app.AppCompatActivity; 5 import androidx.navigation.NavController; 6 import androidx.navigation.Navigation; 7 import androidx.navigation.ui.NavigationUI; 8 9 import android.content.DialogInterface; 10 import android.os.Bundle; 11 12 public class MainActivity extends AppCompatActivity { 13 NavController controller; 14 15 @Override 16 protected void onCreate(Bundle savedInstanceState) { 17 super.onCreate(savedInstanceState); 18 setContentView(R.layout.activity_main); 19 controller = Navigation.findNavController(this, R.id.fragment); 20 NavigationUI.setupActionBarWithNavController(this, controller); 21 } 22 23 @Override 24 public boolean onSupportNavigateUp() { 25 if (controller.getCurrentDestination().getId() == R.id.questionFragment) { 26 AlertDialog.Builder builder = new AlertDialog.Builder(this); 27 builder.setTitle(getString(R.string.quit_dialog_title)); 28 builder.setPositiveButton(R.string.dialog_positive_message, new DialogInterface.OnClickListener() { 29 @Override 30 public void onClick(DialogInterface dialog, int which) { 31 controller.navigateUp(); 32 } 33 }); 34 builder.setNegativeButton(R.string.dialog_negative_message, new DialogInterface.OnClickListener() { 35 @Override 36 public void onClick(DialogInterface dialog, int which) { 37 38 } 39 }); 40 AlertDialog dialog = builder.create(); 41 dialog.show(); 42 } else if (controller.getCurrentDestination().getId() == R.id.titleFragment) { 43 finish(); 44 } else { 45 controller.navigate(R.id.titleFragment); 46 } 47 return super.onSupportNavigateUp(); 48 } 49 50 @Override 51 public void onBackPressed() { 52 onSupportNavigateUp(); 53 } 54 }
当点击返回键时会弹出提示框确认是否离开。
四、本地化
完整的App可以适应手机语言来改变自己所显示的语言
strings.xml
1 <resources> 2 <string name="app_name">CalculationTest</string> 3 4 <!-- TODO: Remove or change this placeholder text --> 5 <string name="hello_blank_fragment" translatable="false">Hello blank fragment</string> 6 <string name="title_message">Calculation Test</string> 7 <string name="title_image_info" translatable="false">title image</string> 8 <string name="title_button_message">Enter</string> 9 <string name="high_score_message">High Score:%d</string> 10 <string name="button0" translatable="false">0</string> 11 <string name="button1" translatable="false">1</string> 12 <string name="button2" translatable="false">2</string> 13 <string name="button3" translatable="false">3</string> 14 <string name="button4" translatable="false">4</string> 15 <string name="button5" translatable="false">5</string> 16 <string name="button6" translatable="false">6</string> 17 <string name="button7" translatable="false">7</string> 18 <string name="button8" translatable="false">8</string> 19 <string name="button9" translatable="false">9</string> 20 <string name="buttonClear" translatable="false">C</string> 21 <string name="buttonSubmit">OK</string> 22 <string name="equal_symbol" translatable="false">=</string> 23 <string name="question_mark" translatable="false">?</string> 24 <string name="current_score">Score:%d</string> 25 <string name="input_indicator">Your Answer:</string> 26 <string name="win_image_message" translatable="false">win image</string> 27 <string name="lose_image_message" translatable="false">lose image</string> 28 <string name="lose_message">You Lose!</string> 29 <string name="win_message">You Win!</string> 30 <string name="lose_score_message">Your Score:%d</string> 31 <string name="win_score_message">New Record:%d</string> 32 <string name="button_back_to_title">Back</string> 33 <string name="answer_correct_message">Correct!Go On!</string> 34 <string name="quit_dialog_title">Are you sure to quit?</string> 35 <string name="dialog_positive_message">OK</string> 36 <string name="dialog_negative_message">Cancel</string> 37 <string name="title_nav_message">Welcome</string> 38 <string name="question_nav_message">Testing</string> 39 <string name="win_nav_message">Win</string> 40 <string name="lose_nav_message">Lose</string> 41 </resources>
strings.xml(zh-rCN)
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <string name="app_name">口算测试</string> 4 <string name="answer_correct_message">回答正确! 请继续!</string> 5 <string name="buttonSubmit">确定</string> 6 <string name="button_back_to_title">返回</string> 7 <string name="current_score">得分:%d</string> 8 <string name="dialog_negative_message">取消</string> 9 <string name="dialog_positive_message">确定</string> 10 <string name="high_score_message">最高纪录:%d</string> 11 <string name="title_button_message">进入</string> 12 <string name="win_score_message">创造新纪录:%d</string> 13 <string name="win_message">挑战成功!</string> 14 <string name="title_message">口算测试</string> 15 <string name="quit_dialog_title">确定离开?</string> 16 <string name="lose_score_message">你的得分:%d</string> 17 <string name="lose_message">挑战失败!</string> 18 <string name="input_indicator">请开始答题:</string> 19 <string name="question_nav_message">测试</string> 20 <string name="title_nav_message">欢迎</string> 21 <string name="win_nav_message">胜利</string> 22 <string name="lose_nav_message">失败</string> 23 </resources>