说在前面:

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();
}

Android-寒假学习-阶段总结(20集)-口算测试APP的更多相关文章

  1. 小学四则运算口算练习app

    目标: 第一次尝试做APP,这次做的东西不是很麻烦,做出一个口算练习的加减乘除的页面,使用者做题,设有答案页,进行核对! 核心部分是出题页面的程序,还有答案页的程序.不设置登录注册页面.冲刺时间:一周 ...

  2. Android开发学习路线的七个阶段和步骤

    Android开发学习路线的七个阶段和步骤           Android学习参考路线     第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和St ...

  3. Android开发学习之路--Android系统架构初探

    环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...

  4. 史上最全的Android开发学习教程集锦【初学者】

    根据Google的报告,截止2017年5月为止,Android活跃用户已超过20亿,并还在持续增长中.Android系统在几个主要的市场上已超过了iOS系统,特别是在美国,欧洲和日本,然而苹果确实在中 ...

  5. Android自动化学习笔记:编写MonkeyRunner脚本的几种方式

    ---------------------------------------------------------------------------------------------------- ...

  6. Android开发学习之LauncherActivity开发启动的列表

    Android开发学习之LauncherActivity开发启动的列表 创建项目:OtherActivity 项目运行结果:   建立主Activity:OtherActivity.java [jav ...

  7. Android Animation学习(二) ApiDemos解析:基本Animatiors使用

    Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独 ...

  8. Android 布局学习之——Layout(布局)具体解释二(常见布局和布局參数)

     [Android布局学习系列]   1.Android 布局学习之--Layout(布局)具体解释一   2.Android 布局学习之--Layout(布局)具体解释二(常见布局和布局參数)   ...

  9. 大量Javascript/JQuery学习教程电子书合集

    [推荐分享]大量Javascript/JQuery学习教程电子书合集,送给有需要的人   不收藏是你的错^_^. 经证实,均可免费下载. 资源名称 资源大小   15天学会jQuery(完整版).pd ...

随机推荐

  1. 【转】stm32 IAP升级程序

      一.什么是IAP,为什么要IAP       IAP即为In Application Programming(在应用中编程),一般情况下,以STM32F10x系列芯片为主控制器的设备在出厂时就已经 ...

  2. 加拿大Assignment写作如何靠第一句话来吸睛?

    最近有留学加拿大的同学咨询我们如何写好assignment的首句,关于话题背景的引入,如何才能自然精妙,让老师对后文充满期待.小编用一句话总结今天的策略:陈述一个跟话题直接相关的事实.“直接相关”,保 ...

  3. 记一次海洋cms任意代码执行漏洞拿shell(url一句话)

    实验环境:海洋CMS6.54(后续版本已该洞已补) 1.后台登录尝试 这个站点是个测试站,站里没什么数据. 进入admin.php,是带验证码的后台登录系统,没有验证码的可以用bp爆破.有验证码的也有 ...

  4. greenplum 存储过程 索引信息

    涉及的索引表 参考:http://blog.nbhao.org/1539.html pg_index pg_indexes pg_stat_all_indexes # 记录当前数据库中所有的索引的使用 ...

  5. mongodb- 备份和导入备份

    一.使用 mongodump 命令备份数据 mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表 -o 文件存放路径 参数说明: -h 指明数据库宿主机 ...

  6. ROS常用库(三)API学习之常用common_msgs(上)

    一.概述 common_msgs包含其他ROS软件包广泛使用的消息.这些消息包括动作消息(actionlib_msgs),诊断消息(diagnostic_msgs),几何图元(geometry_msg ...

  7. 在 Linux 上实现一段时间后自动登出非活动用户

    参考 编辑 ~/.bashrc 或 ~/.bash_profile 文件: $ vi ~/.bashrc 或, $ vi ~/.bash_profile 将下面行加入其中: TMOUT=100 这会让 ...

  8. MyBatis Generator 下划线转驼峰命名

    MyBatis Generator配置文件--指定生成实体类使用实际的表列名作为实体类的属性名 table标签下的设置属性useActualColumnNames用于指定生成实体类时是否使用实际的列名 ...

  9. 032.SAP上用户无法打开PPE模块,查看并开通用户的PPE权限

    01. 用户使用PPE模块之后,提示没有为iPPE工作台分配一个用户参数,如图所示: 02. 如果是管理员账号,则可以点击右下角的问号,来到下面界面 03.点击iPPE 用户分配者几个蓝色的字,进入下 ...

  10. 012.Oracle数据库,字符串文本大小写转换,转大写,转小写,首字母大写

    /*转大写*/ SELECT UPPER(TITLE_EN) FROM ME_EO WHERE ( ISSUE_DATE BETWEEN to_date( '2017-02-04', 'yyyy-MM ...