四則運算APP版
(一)四則運算APP版
這這個Demo的目的就是強化一下本週學習的Android的Jetpack裡的新內容,接下來我將通過這個Demo來展示我所學到的新知識。
先列出新學到的知識:ViewModel,Navigation,MutableLiveData,ViewModelSaveState,SharedPreferences,AndroidViewModel,DataBinding
設計思路:
UI設計思路:
一共四個頁面:首頁,習題頁,成功頁,失敗頁
將這四個頁面通過Navigation連線起來形成一條邏輯關係。
接下來就是對每個頁面進行設計。
首頁:一個TextView和一個ImageView還有一個Button,頂部還有一個最高分Textview,通過button來進入出題頁面
<?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.example.calculation.MyViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout 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/CalName" android:textSize="@dimen/huge_size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline2" app:layout_constraintStart_toStartOf="@+id/guideline" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.106" /> <ImageView android:id="@+id/imageView" android:layout_width="320dp" android:layout_height="349dp" android:contentDescription="@string/title_image" android:src="@drawable/size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="w,1:1" app:layout_constraintEnd_toStartOf="@+id/guideline2" app:layout_constraintHorizontal_bias="0.56" app:layout_constraintStart_toStartOf="@+id/guideline" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="0dp" android:layout_height="wrap_content" android:text="@string/title_button" 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.862" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/higer_score(data.highScore)}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.883" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.036" tools:text="High Score:%d" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
出題頁面:頂部一個textview代表目前的得分情況,中間是一個算式,下面是你的答案,接下來是4行3列,12個按鈕代表你的操作。
<?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.example.calculation.MyViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout 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.33" /> <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.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.5" /> <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.6" /> <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.7" /> <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.8" /> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/Current_Score(data.currentScore)}" app:layout_constraintBottom_toTopOf="@+id/guideline3" app:layout_constraintEnd_toStartOf="@+id/guideline9" app:layout_constraintHorizontal_bias="0.537" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/guideline3" app:layout_constraintVertical_bias="0.473" tools:text="Score:0" /> <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/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/huge_size" android:text="@{String.valueOf(data.leftNumber)}" app:layout_constraintBottom_toBottomOf="@+id/textView5" app:layout_constraintEnd_toStartOf="@+id/textView5" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/textView5" tools:text="1" /> <TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/huge_size" android:text="@{String.valueOf(data.operator)}" app:layout_constraintBottom_toBottomOf="@+id/textView6" app:layout_constraintEnd_toStartOf="@+id/textView6" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/textView4" app:layout_constraintTop_toTopOf="@+id/textView6" tools:text="+" /> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/huge_size" android:text="@{String.valueOf(data.rigthNumber)}" app:layout_constraintBottom_toBottomOf="@+id/textView7" app:layout_constraintEnd_toStartOf="@+id/textView7" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/textView5" app:layout_constraintTop_toTopOf="@+id/textView7" tools:text="2" /> <TextView android:id="@+id/textView7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="=" android:textSize="@dimen/huge_size" app:layout_constraintBottom_toBottomOf="@+id/textView8" app:layout_constraintEnd_toStartOf="@+id/textView8" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/textView6" app:layout_constraintTop_toTopOf="@+id/textView8" tools:text="=" /> <TextView android:id="@+id/textView8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/Cal_Answer" android:textSize="@dimen/huge_size" app:layout_constraintBottom_toTopOf="@+id/guideline4" app:layout_constraintEnd_toStartOf="@+id/guideline9" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/textView7" app:layout_constraintTop_toTopOf="@+id/guideline4" /> <TextView android:id="@+id/textView9" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Your Answer:" android:textSize="@dimen/mid_size" 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="1" android:textSize="@dimen/button_size" app:layout_constraintBottom_toTopOf="@+id/guideline10" app:layout_constraintEnd_toStartOf="@+id/button2" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/guideline6" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2" android:textSize="@dimen/button_size" 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="3" android:textSize="@dimen/button_size" 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/button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="4" android:textSize="@dimen/button_size" app:layout_constraintBottom_toTopOf="@+id/guideline11" app:layout_constraintEnd_toStartOf="@+id/button5" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/guideline10" /> <Button android:id="@+id/button5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="5" android:textSize="@dimen/button_size" 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/button6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="6" android:textSize="@dimen/button_size" 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/button7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="7" android:textSize="@dimen/button_size" app:layout_constraintBottom_toTopOf="@+id/guideline12" app:layout_constraintEnd_toStartOf="@+id/button8" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/guideline11" /> <Button android:id="@+id/button8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="8" android:textSize="@dimen/button_size" 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="9" android:textSize="@dimen/button_size" 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="Clear" android:textSize="@dimen/button_size" app:layout_constraintBottom_toTopOf="@+id/guideline7" app:layout_constraintEnd_toStartOf="@+id/button0" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/guideline8" app:layout_constraintTop_toTopOf="@+id/guideline12" /> <Button android:id="@+id/button0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="@dimen/button_size" 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="OK" android:textSize="@dimen/button_size" 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>
成功頁面:一個Imageview笑臉,兩個Textview還有一個Button來返回首頁
<?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.example.calculation.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/guideline13" 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/guideline14" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.35" /> <ImageView android:id="@+id/imageView2" android:layout_width="0dp" android:layout_height="0dp" android:contentDescription="@string/image_win" android:src="@drawable/ic_sentiment_satisfied_black_24dp" app:layout_constraintBottom_toTopOf="@+id/guideline14" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline13" /> <TextView android:id="@+id/textView10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="恭喜你!創下新紀錄" android:textSize="@dimen/bige_size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline14" app:layout_constraintVertical_bias="0.1" /> <TextView android:id="@+id/textView11" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/New_Score(data.highScore)}" android:textSize="@dimen/bige_size" 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.3" tools:text="你的成績是:%d" /> <Button android:id="@+id/button10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline14" app:layout_constraintVertical_bias="0.5" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>View Code
失敗頁面:一個Imageview哭臉,兩個Textview還有一個Button來返回首頁
<?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.example.calculation.MyViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LoseFragment"> <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.1" /> <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.35" /> <ImageView android:id="@+id/imageView3" android:layout_width="0dp" android:layout_height="0dp" android:src="@drawable/ic_sentiment_dissatisfied_black_24dp" app:layout_constraintBottom_toTopOf="@+id/guideline16" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline15" /> <TextView android:id="@+id/textView13" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/New_Score(data.currentScore)}" android:textSize="@dimen/bige_size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline16" app:layout_constraintVertical_bias="0.3" tools:text="你的成績是:%d" /> <Button android:id="@+id/button11" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline16" app:layout_constraintVertical_bias="0.5" /> <TextView android:id="@+id/textView14" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="挑戰失敗!" android:textSize="@dimen/bige_size" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imageView3" app:layout_constraintVertical_bias="0.1" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>View Code
程式設計:
首先是設計我們的MyViewModel裡的資料,有最高分,目前得分,左運算元,右運算元,操作符,答案
通過SharedPreferences來儲存資料,livedata可以隨時的重新整理資料,故用它來顯示資料。
package com.example.calculation; 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 androidx.lifecycle.ViewModel; import java.util.Random; public class MyViewModel extends AndroidViewModel { private SavedStateHandle handle; private static String KEY_HIGH_SCORE="key_high_score"; private static String KEY_LEFT_NUMBER="key_left_number"; private static String KEY_RIGHT_NUMBER="key_right_number"; private static String KEY_OPERATOR="key_operator"; private static String KEY_ANSWER="key_answer"; private static String SAVE_SHP_DATA_NAME="save_shp_data_name"; private static String KEY_CURRENT_SCORE="key_current_score"; 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,shp.getInt(KEY_HIGH_SCORE,0)); handle.set(KEY_LEFT_NUMBER,0); handle.set(KEY_RIGHT_NUMBER,0); handle.set(KEY_OPERATOR,"+"); handle.set(KEY_ANSWER,0); handle.set(KEY_CURRENT_SCORE,0); } this.handle=handle; } public MutableLiveData<Integer> getLeftNumber(){ return handle.getLiveData(KEY_LEFT_NUMBER); } public MutableLiveData<Integer> getRigthNumber(){ return handle.getLiveData(KEY_RIGHT_NUMBER); } public MutableLiveData<String> getOperator(){ return handle.getLiveData(KEY_OPERATOR); } public MutableLiveData<Integer> getHighScore(){ return handle.getLiveData(KEY_HIGH_SCORE); } public MutableLiveData<Integer> getCurrentScore(){ return handle.getLiveData(KEY_CURRENT_SCORE); } public MutableLiveData<Integer> getAnswer(){ return handle.getLiveData(KEY_ANSWER); } public void setCurrentScore(){ handle.set(KEY_CURRENT_SCORE,0); } void generator(){ int level=100; Random random=new Random(); int a=random.nextInt(level)+1; int b=random.nextInt(level)+1; if(a%4==0){ getOperator().setValue("+"); if(a>b){ getAnswer().setValue(a); getLeftNumber().setValue(b); getRigthNumber().setValue(a-b); }else{ getOperator().setValue("+"); getAnswer().setValue(b); getLeftNumber().setValue(a); getRigthNumber().setValue(b-a); } } else if(a%4==1){ getOperator().setValue("-"); if(a>b){ getAnswer().setValue(a-b); getLeftNumber().setValue(a); getRigthNumber().setValue(b); }else{ getOperator().setValue("-"); getAnswer().setValue(b-a); getLeftNumber().setValue(b); getRigthNumber().setValue(a); } } else if(a%4==2){ getOperator().setValue("*"); getLeftNumber().setValue(a); getRigthNumber().setValue(b); getAnswer().setValue(a*b); } else if(a%4==3){ getOperator().setValue("/"); while(a%b!=0){ a=random.nextInt(level)+1; b=random.nextInt(level)+1; } getLeftNumber().setValue(a); getRigthNumber().setValue(b); getAnswer().setValue(a/b); } } 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(); } void answerCurrent(){ getCurrentScore().setValue(getCurrentScore().getValue()+1); if(getCurrentScore().getValue()>getHighScore().getValue()){ getHighScore().setValue(getCurrentScore().getValue()); win_flag=true; } generator(); } }View Code
TieleFragment的設計:設計一個按鈕的繫結事件,進行跳轉到出題頁面
package com.example.calculation; import android.app.AppComponentFactory; import android.app.Application; import android.content.pm.ApplicationInfo; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; 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.example.calculation.databinding.FragmentTitleBinding; /** * A simple {@link Fragment} subclass. */ public class TitleFragment extends Fragment{ public TitleFragment() { // Required empty public constructor } @Override public View onCreateView(@NonNull LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { FragmentTitleBinding binding; binding= DataBindingUtil.inflate(inflater,R.layout.fragment_title,container,false); MyViewModel myViewModel = ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(),requireActivity())).get(MyViewModel.class); binding.setData(myViewModel); binding.setLifecycleOwner(requireActivity()); binding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NavController controller=Navigation.findNavController(v); controller.navigate(R.id.action_titleFragment_to_questionFragment); } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_title, container, false); } }View Code
QuestionFragment的設計:通過按鈕點選來獲取使用者的答案,然後從資料裡獲取當前的viewmodel,判斷結果是否相同,之後進行相應的操作。
裡面有程式碼註釋
package com.example.calculation; 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 android.widget.Toast; import com.example.calculation.databinding.FragmentQuestionBinding; /** * A simple {@link Fragment} subclass. */ public class QuestionFragment extends Fragment { public QuestionFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { final MyViewModel myViewModel; myViewModel= ViewModelProviders.of(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),requireActivity())).get(MyViewModel.class); //獲取運算表示式 myViewModel.generator(); //設定初始得分為0 myViewModel.setCurrentScore(); //獲取頁面的控制binding final FragmentQuestionBinding binding; binding= DataBindingUtil.inflate(inflater,R.layout.fragment_question,container,false); //設定資料與生命週期 binding.setData(myViewModel); binding.setLifecycleOwner(requireActivity()); //builder用來儲存使用者輸入的資料 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: //清楚代表使用者的輸入長度未0 builder.setLength(0); break; } if(builder.length()==0){ binding.textView9.setText("請輸入你的答案:"); }else{ //顯示到UI頁面上 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) { if(builder.length()!=0) { //當答案相同時 if (Integer.valueOf(builder.toString()).intValue() == myViewModel.getAnswer().getValue()) { myViewModel.answerCurrent(); builder.setLength(0); binding.textView9.setText("回答正確! 請繼續!"); } else { NavController controller = Navigation.findNavController(v); if (myViewModel.win_flag) { //當創造新紀錄時,進入成功頁面 controller.navigate(R.id.action_questionFragment_to_winFragment); myViewModel.win_flag = false; myViewModel.save(); } else { //否則進入失敗頁面 controller.navigate(R.id.action_questionFragment_to_loseFragment); } } }else{ Toast.makeText(v.getContext(), "請輸入答案", Toast.LENGTH_SHORT).show(); } } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_question, container, false); } }View Code
WinFragment的設計:設定它的返回按鈕,與LoseFragment一樣
package com.example.calculation; import android.os.Bundle; import androidx.databinding.DataBindingUtil; import androidx.fragment.app.Fragment; import androidx.lifecycle.SavedStateHandle; 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.example.calculation.databinding.FragmentWinBinding; /** * A simple {@link Fragment} subclass. */ public class WinFragment extends Fragment { public WinFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { MyViewModel myViewModel; myViewModel= ViewModelProviders.of(requireActivity(), new SavedStateViewModelFactory(requireActivity().getApplication(),requireActivity())).get(MyViewModel.class); FragmentWinBinding binding; binding= DataBindingUtil.inflate(inflater,R.layout.fragment_win,container,false); binding.setData(myViewModel); binding.setLifecycleOwner(requireActivity()); binding.button10.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NavController controller= Navigation.findNavController(v); controller.navigate(R.id.action_winFragment_to_titleFragment); } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_win, container, false); } }View Code
package com.example.calculation; 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.example.calculation.databinding.FragmentLoseBinding; /** * A simple {@link Fragment} subclass. */ public class LoseFragment extends Fragment { public LoseFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { MyViewModel myViewModel; myViewModel= ViewModelProviders.of(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),requireActivity())).get(MyViewModel.class); FragmentLoseBinding binding; binding= DataBindingUtil.inflate(inflater,R.layout.fragment_lose,container,false); binding.setData(myViewModel); binding.setLifecycleOwner(requireActivity()); binding.button11.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NavController controller= Navigation.findNavController(v); controller.navigate(R.id.action_loseFragment_to_titleFragment); } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_lose, container, false); } }View Code
MainActivity的設計:用來設定左上角的返回與手機左下方左三角的返回
package com.example.calculation; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.ui.NavigationUI; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; public class MainActivity extends AppCompatActivity { NavController controller; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); controller= Navigation.findNavController(this,R.id.fragment); NavigationUI.setupActionBarWithNavController(this,controller); } //設定頁面的左上角的返回操作 @Override public boolean onSupportNavigateUp() { if(controller.getCurrentDestination().getId()==R.id.questionFragment){ AlertDialog.Builder builder=new AlertDialog.Builder(this); builder.setTitle("你確定要退出嗎?"); builder.setPositiveButton("確定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { controller.navigateUp(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); AlertDialog dialog=builder.create(); dialog.show(); }else{ controller.navigate(R.id.titleFragment); } return super.onSupportNavigateUp(); } //設定手機的左三角的返回操作 @Override public void onBackPressed() { onSupportNavigateUp(); } }View Code
整個專案到此完結。。。
花費時間:
2020/3/29:上午10:00-11:10,休息10分鐘,11:30-12:30,
2020/3/29:下午15:00-15:45,吃東西喝水10分鐘,16:00-19:00,吃飯30分鐘。
2020/3/29:晚上19:30-20:45,完成。
共花費:420分鐘,程式碼量:450行,UI設計程式碼除外。
&n