Android-寒假学习-阶段总结(20集)-口算测试APP
说在前面:
1、视频教程:https://www.bilibili.com/video/av60445113/?spm_id_from=333.788.videocard.0
2、老师的源码:https://github.com/longway777/Android-2019-Demo-CalculationTest
3、我的源码:https://github.com/xiaotian12-call/Learning/tree/0c345ee43df1f3bb0bc161087880b416a579a707
一、界面的搭建:
1、创建四个界面
1)TitleFragment.java&fragment_title.xml
(注:1、imageview所用图片是网上随意下载的;2、右上角的"high score :%d",需要与viewmodel中的数据绑定;3、点击Entry,进入答题界面:
@Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final MyViewModel myViewModel; myViewModel = ViewModelProviders.of(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),requireActivity())).get(MyViewModel.class); FragmentTitleBinding binding; 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 controller = Navigation.findNavController(v); controller.navigate(R.id.action_titleFragment_to_questionFragment); myViewModel.getCurrentScore().setValue(0); myViewModel.generator(); } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_title, container, false); }
)
2)QuestionFragment.java&fragment_question.xml
(注:1、0-9和重置键设置监听:
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.buttonclaer: builder.setLength(0); break; } if (builder.length() == 0) { binding.textView9.setText(getString(R.string.input_hint)); } 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.buttonclaer.setOnClickListener(listener);
2、提交答案设置监听:
binding.buttonsubmit.setOnClickListener(new View.OnClickListener() { @SuppressWarnings("ConstantConditions") @Override public void onClick(View v) { if (builder.length() == 0) { builder.append("-1"); } if (Integer.valueOf(builder.toString()).intValue() == myViewModel.getAnswer().getValue()) { myViewModel.answerCorrect(); builder.setLength(0); binding.textView9.setText(R.string.answer_currect_message); //builder.append(getString(R.string.answer_corrrect_message)); } 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); } } } }); return binding.getRoot(); // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_question, container, false); }
)
3)WinFragment.java&fragment_win.xml
(注:1、矢量图的创建:
2、back键的监听及动作:
@Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment 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.buttonWb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Navigation.findNavController(v).navigate(R.id.action_winFragment_to_titleFragment); } }); return binding.getRoot(); }
)
4)LostFragment.java&fragment_lost.xml
(注:back键的监听及动作:
@Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment 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.buttonLB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Navigation.findNavController(v).navigate(R.id.action_loseFragment_to_titleFragment); } }); return binding.getRoot(); }
)
2、创建导航图表导入LoseFragment,确定页面跳转关系
1)创建navigation:
2)导入fargment:
3)确定页面跳转关系
二、数据与逻辑的处理
1、数据规划,使用viewmodel管理:最高纪录 :highScore、算式左操作数:leftNumber、算式右操作数:rightNumber、运算符:operator、答案:answer、当前得分:currentScore。
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"; 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>getRightNumber(){ 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); }
2、生成运算式
1)设置挑战难度:20(20以内的运算);
2)生成两个随机数,当是加法运算时、以大的作为answer,小的作为leftNumber,大减小作为rightNumber;当为减法运算时,大的为被减数,小的为减数,大的减小的是答案。
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); } } }
3)破纪录,保存highScore
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(); }
4)正确时,判断是否需要更新highScore,并生成新的算式
void answerCorrect(){ getCurrentScore().setValue(getCurrentScore().getValue() + 1 ); if (getCurrentScore().getValue() > getHighScore().getValue()) { getHighScore().setValue(getCurrentScore().getValue()); win_flag = true; } generator(); }