数字小游戏

此程序集合了页面布局、设置颜色、动画演示、背景音乐、添加功能按钮及对话框技术。

源码下载地址:https://pan.baidu.com/s/1FlMobWYA-tYF2T__feq-cA

Apk下载地址:https://pan.baidu.com/s/1h-63IkKiOPCtqQUJNCRA9A


开发背景:

   现代教学的思路是寓教于乐,如何让小朋友在玩中学到知识是众多手机App开发者需要攻克的难关。此App开发的初衷是通过漂亮的界面、欢快的音乐和有趣的动画演示吸引小朋友, 使其在玩的过程中学会书写0-9十个数字。


                                                            系统功能结构图


                                                                                 业务流程图



系统文件组织结构:

说明一点:此处“关于”部分的业务没有编写。

话不多说,开始分析这个App吧:

1、startActivity 活动+布局

<!--相对布局头部-->
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/start_bg"
    >
 <!--相对布局尾部-->
</RelativeLayout>
 这个布局没啥好说的,只是单纯一个具有背景的欢迎界面。

public class StartActivity extends Activity {    //StartActivity类头部

    @Override
    protected void onCreate(Bundle savedInstanceState) {    //onCreate() 方法头部
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);

        Timer timer = new Timer();

        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                startActivity(new Intent(StartActivity.this, MainActivity.class));
                finish();
            }
        };
     timer.schedule(task,1200);

    }            //onCreate()方法尾部

  }                                                     //StartActivity类尾部

 为了使启动界面全屏显示, 让此活动继承Activity, 并在清单中作如下设置:

<activity
            android:name=".StartActivity"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen">  //设置全屏
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

活动的任务也很简单, 只是创建了一个定时器 使得定时器任务在设定时间后进行页面的跳转。

2、MainActivity活动+布局

<!--相对布局头部-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/main_bg"
    >

    <!--开始游戏按钮-->
    <Button
        android:id="@+id/start"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:layout_marginBottom="100dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/play_btn"
        android:onClick="OnPlay"
        />

    <!--背景音乐按钮-->
    <Button
        android:id="@+id/btn_music"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_alignParentTop="true"
        android:background="@drawable/btn_music1"
        android:onClick="OnMusic"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="20dp"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="by Yuyang"
        android:textSize="16sp"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="30dp"
        android:layout_marginBottom="10dp"
        android:textColor="@android:color/white"
        />
   <!--相对布局尾部-->
</RelativeLayout>

 在最外层布局中设置背景图片,在布局文件中 放置了两个按钮控件 一个文本控件。用于开启游戏事件及设置背景音乐的开关。

主布局就这么多东西, 很简约。。。

   

public class MainActivity extends Activity {  //MainActivity类头部

    static boolean isPlay = true;  //设置音乐播放状态变量
    MediaPlayer mediaPlayer;   //定义音乐播放器对象
    private Button music_btn;   //定义控制音乐播放按钮


    @Override
    protected void onCreate(Bundle savedInstanceState) {     //onCreate() 方法头部
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        music_btn = (Button) findViewById(R.id.btn_music);
        PlayMusic();  //播放音乐


    }  //onCreate() 方法的尾部

     //主界面停止时, 背景音乐停止
    @Override
    protected void onStop() {
        super.onStop();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
    }


         //主界面清空所占资源, 背景音乐停止,音乐资源清空
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();   //清空资源
            mediaPlayer = null;    //设置播放器为空
        }
    }

    //该方法实现从另外一个界面切换到主界面时, 根据音乐播放状态播放音乐
    @Override
    protected void onRestart() {
        super.onRestart();
        if (isPlay == true) {
            PlayMusic();
        }
    }

    private void PlayMusic() {
        //创建音乐播放器对象并加载播放音乐文件
        mediaPlayer = MediaPlayer.create(this, R.raw.main_music);
        mediaPlayer.setLooping(true);      //设置循环播放
        mediaPlayer.start();     //开启播放   }

    public void OnPlay(View v){   //单击事件,选择进入数字界面

        startActivity(new Intent(MainActivity.this, SelectActivity.class));
    }
       /**
     * 单击事件, 控制背景音乐的播放
     * @param v
     */
    public void OnMusic(View v){
        if (isPlay == true) {
            if (mediaPlayer != null) {
                mediaPlayer.stop();
                //设置按钮为停止状态
                music_btn.setBackgroundResource(R.drawable.btn_music2);
                isPlay = false;
            }
        } else {
            PlayMusic();
            music_btn.setBackgroundResource(R.drawable.btn_music1);
            isPlay = true;
          }
       }
    }   //MainActivity 类的尾部

 在onCreate() 方法中 获取音乐按钮控件, 以及创建 PlayMusic() 方法,在此方法中创建播放器并加载音乐文件,使得背景音乐和主活动同时启动。

 在OnMusic() 单击事件中, 完成主活动背景音乐的开启和关闭, 注意 只有当音乐处于播放状态和音乐播放器不为空 两者同时满足的情况下 才可停止音乐播放 以及改变播放状态。

 onStop() 方法, 用于实现页面跳转时, 停止当前背景音乐。

 onDestory() 方法, 用于实现当游戏主界面清空所占内存资源时, 停止背景音乐 并释放音乐资源所占内存。

 onRestory() 方法,用于实现从其他界面返回主界面时, 根据音乐播放状态判断是否播放音乐。

 主活动分析完成。

3、SelectAcvivity 活动+布局

<!--表格布局头部-->
<TableLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
    >
    <!--显示第一行1至3数字-->
    <TableRow
        android:layout_weight="1"
        >
      <!--显示数字1图片-->
           <ImageView
               android:layout_weight="1"
               android:layout_width="0dp"
               android:layout_margin="10dp"
               android:onClick="OnOne"
               android:src="@drawable/on1_24_1"
               />

        <!--显示数字2图片-->
        <ImageView
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_margin="10dp"
            android:onClick="OnTwo"
            android:src="@drawable/on2_24"
            />

        <!--显示数字3图片-->
        <ImageView
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_margin="10dp"
            android:onClick="OnThree"
            android:src="@drawable/on3_24"
            />
    </TableRow>
    。。。
    <!--显示第四行0数字-->
    <TableRow
        android:layout_weight="1"
        >
    <!--显示数字0图片-->
    <ImageView
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_margin="10dp"
        android:onClick="OnZero"
        android:src="@drawable/on0_24"
        />

        <!--占位-->
        <ImageView
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:layout_width="0dp"
            />
        <!--占位-->
        <ImageView
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:layout_width="0dp"
            />
    </TableRow>

    <!--表格布局尾部-->
</TableLayout>

   TableLayout (表格布局), <TableRow android:layout_weight="1"></TableRow> (行标签) 行数为4 设置每行高度占屏幕的1/4。 因此控件中也就无需再设置控件的高度。

  

public class SelectActivity extends Activity {    //SelectActivity 类头部

    MediaPlayer mediaPlayer;   //定义音乐播放器
    @Override
    protected void onCreate(Bundle savedInstanceState) {    //onCreate() 方法头部
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_select);

     if (MainActivity.isPlay == true) {
         PlayMusic();
     }
} //onCreate() 方法尾部

    private void PlayMusic() {
        //创建音乐播放器对象并加载音乐文件
        mediaPlayer = MediaPlayer.create(this, R.raw.number_music);
        mediaPlayer.setLooping(true);
        mediaPlayer.start();
    }

    //该方法实现数字界面停止后, 背景音乐停止播放
     @Override
    protected void onStop() {
        super.onStop();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
    }

    //该方法用于数字界面销毁后, 释放音乐资源
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null){
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    //该方法用于从另一界面返回选择数字界面是, 根据播放音乐状态播放音乐


    @Override
    protected void onRestart() {
        super.onRestart();
        if (MainActivity.isPlay == true){
            PlayMusic();
        }
   }

   public void OnOne(View v){   //单击事件, 跳转到书写数字1界面
    startActivity(new Intent(SelectActivity.this, OneActivity.class));

   }
    public void OnTwo(View v){   //单击事件  进入数字2书写界面
        //当前界面跳转至数字2书写界面
        startActivity(new Intent(SelectActivity.this, TwoActivity.class));
    }
    public void OnThree(View v){   //单击事件  进入数字3书写界面
        //当前界面跳转至数字3书写界面
        startActivity(new Intent(SelectActivity.this, ThreeActivity.class));
    }
    public void OnFour(View v){   //单击事件  进入数字4书写界面
        //当前界面跳转至数字4书写界面
        startActivity(new Intent(SelectActivity.this, FourActivity.class));
    }
    public void OnFive(View v){   //单击事件  进入数字5书写界面
        //当前界面跳转至数字5书写界面
        startActivity(new Intent(SelectActivity.this, FiveActivity.class));
    }
    public void OnSix(View v){   //单击事件  进入数字6书写界面
        //当前界面跳转至数字6书写界面
        startActivity(new Intent(SelectActivity.this, SixActivity.class));
    }
    public void OnSeven(View v){   //单击事件  进入数字7书写界面
        //当前界面跳转至数字7书写界面
        startActivity(new Intent(SelectActivity.this, SevenActivity.class));
    }
    public void OnEight(View v){   //单击事件  进入数字8书写界面
        //当前界面跳转至数字8书写界面
        startActivity(new Intent(SelectActivity.this, EightActivity.class));
    }
    public void OnNine(View v){   //单击事件  进入数字9书写界面
        //当前界面跳转至数字9书写界面
        startActivity(new Intent(SelectActivity.this, NineActivity.class));
    }
    public void OnZero(View v){   //单击事件  进入数字8书写界面
        //当前界面跳转至数字8书写界面
        startActivity(new Intent(SelectActivity.this, ZeroActivity.class));
    }


}//SelectActivity 类尾部

 在SelectActivity 活动中,也有背景音乐的一系列操作,在onCreate() 方法中根据主活动中的音乐按钮控制SelectActivity 活动中 的音乐播放正太。 其余与主活动中的实现相同, 这里不在赘述。。。

 接着是一串的 单击事件, 完成各个数字0-9书写界面的跳转.。。。

 虽然有十个数字活动, 但其实现的过程都相似, 在这里就以OneActivity 活动为例子, 进行详细分析:

4、OneActivity 活动+布局

 
 
 
 
<!--外层线性布局头部-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/LinearLayout_number"
    >

    <Button
        android:layout_marginTop="30dp"
        android:layout_marginLeft="15dp"
        android:background="@drawable/demo_btn"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:onClick="OnYS"
        />

    <!--书写区域线性布局头部-->

    <LinearLayout
        android:id="@+id/LinearLayout1"
        android:gravity="center"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/iv_frame"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="书写至末尾才可完成挑战哦ヾ(✿゚▽゚)ノ"
            android:textColor="@android:color/black"
            />

    </LinearLayout>
  <!--外层线性布局尾部-->

</LinearLayout>
此布局为垂直线性布局, 布局中只有 一个演示按钮, 以及嵌套了以一个垂直线性布局 作为书写区域, 在子布局中
添加了一个ImageView 控件, 用于显示书写的数字图片。



public class OneActivity extends Activity{  //OneActivity类的头部

    public mCustomProgressDialog mdialog;   //定义自定义对话框对象
    private ImageView iv_frame;    //定义显示写数字的ImageView控件
    MediaPlayer mediaPlayer;
    int i = 1;                   //图片展示到第几张标记
    float x1;                     //屏幕按下时的x值
    float y1;                  //屏幕按下时的y值
    float x2;//屏幕离开时的x值
    float y2;//屏幕离开时的y值
    float x3;//移动中的坐标x值
    float y3;//移动中的坐标y值
    int igvx; //图片x坐标
    int igvy;//图片y坐标
    int type = 0;//是否可以书写标识, 开关: 1开启; 0关闭
    int widthPixels;//屏幕宽度
    int heightPixels;//屏幕高度
    float scaleWidth;//宽度的缩放比例
    float scaleHeight;//高度的缩放比例
    Timer touchTimer = null;//单击在虚拟按钮上后用于连续动作的计时器
    Bitmap arrdown;     //Bitmap图像处理
    boolean typedialog = true;   //dialog对话框状态
    private LinearLayout linearLayout = null;    //LinearLayout线性布局
;

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {   //onCreate() 方法头部
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_number);

        //如果游戏界面设置为背景音乐为播放音乐状态
        if (MainActivity.isPlay == true) {
            PlayMusic();
        }

        initView();

    }//onCreate() 方法尾部

    public void OnYS(View v){   //创建演示按钮, 单击事件头部
        if (mdialog == null){
            mdialog = new mCustomProgressDialog(this, "演示中单击边缘取消", R.drawable.frame1);
        }
        mdialog.show();    //显示对话框
    }

    private void PlayMusic() {
       mediaPlayer = MediaPlayer.create(this, R.raw.music1);
       mediaPlayer.setLooping(true);
       mediaPlayer.start();
    }

    //实现数字1 界面停止时, 背景音乐停止
     @Override
    protected void onStop() {
        super.onStop();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
    }
      //书写界面1销毁时, 背景音乐停止并释放音乐资源
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;

    }

    private void initView() {

     iv_frame = (ImageView) findViewById(R.id.iv_frame);

     LinearLayout linearLayout = (LinearLayout) findViewById(R.id.LinearLayout1);

     LinearLayout write_layout = (LinearLayout) findViewById(R.id.LinearLayout_number);

     write_layout.setBackgroundResource(R.drawable.bg1);
  //获取屏幕宽度
      widthPixels = this.getResources().getDisplayMetrics().widthPixels;
  //获取屏幕高度
     heightPixels = this.getResources().getDisplayMetrics().heightPixels;
  //因为图片是按1280*720 来准备的,如果是其他分辨率,适应屏幕做准备
     scaleWidth = ((float) widthPixels / 720);
     scaleHeight = ((float) heightPixels / 1280);
     try{

   //通过输入流打开第一张图片
      InputStream is = getResources().getAssets().open("on1_1.png");
      //使用Bitmap解析第一张图片
      arrdown = BitmapFactory.decodeStream(is);
     } catch (IOException e) {
       e.printStackTrace();
     }

    //获取布局的宽高信息
     LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) iv_frame.getLayoutParams();
     //获取图片缩放后的宽度
       layoutParams.width = (int)(arrdown.getWidth() * scaleWidth);
    //获取图片缩放后的高度
     layoutParams.height = (int) (arrdown.getHeight() * scaleHeight);
     //根据图片缩放后的宽高, 设置iv_frame的宽高
      iv_frame.setLayoutParams(layoutParams);
      lodimagep(1);   //调用lodimaged() 方法, 进入页面后加载第一个图片
      linearLayout.setOnTouchListener(new View.OnTouchListener() {   //设置手势判断事件
         @Override
         public boolean onTouch(View v, MotionEvent event) {     //手势按下判断的onTouch()事件
             //通过判断手势按下时获取的坐标位置来判断是否可以进行书写
             switch (event.getAction()){  //获取行动方式头部
                 case MotionEvent.ACTION_DOWN: //手指按下事件
                 //获取手指按下时的坐标
                 x1 = event.getX();    //获取手指按下的x坐标
                 y1 = event.getY();   //获取手指按下的y坐标
                 igvx = iv_frame.getLeft(); //获取手指按下图片的x坐标
                 igvy = iv_frame.getTop();  //获取手指按下图片的y坐标
                     //判断当手指按下的坐标大于图片位置坐标时, 证明手指按下移动, 此时开启书写
                     if (x1 > igvx && x1 < igvx + (int) (arrdown.getWidth() * scaleWidth)
                             && y1 > igvy && y1 < igvy + (int)(arrdown.getHeight() * scaleHeight)){
                         type = 1; //开启书写

                     }else {
                            type = 0; //关闭书写
                     }
                     break;
                 case MotionEvent.ACTION_MOVE:    //手势移动中判
                      x2 = event.getX();
                      y2 = event.getY();
                      igvx = iv_frame.getLeft();
                      igvy = iv_frame.getTop();
                      //下面根据笔画以及手势做图片处理, 滑到不同位置, 加载不同图片
                     if (type == 1){
                         //如果手指按下的 x 坐标大于等于图片的x坐标, 或者小于等于缩放图片的x坐标时
                         if (x2 >= igvx && x2 <= igvx + (int) (arrdown.getWidth() * scaleWidth)) {
                             //如果当前手指按下的Y 坐标小于等于缩放图片的Y 坐标, 或者大于等于图片的Y坐标时
                              if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 && y2 >= igvy) {
                                  lodimagep(1);  //加载第一个图片
                              }
                             //如果当前手指按下的Y坐标小于等于小于等于缩放图片的Y 坐标
                             else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 2){
                                  lodimagep(2);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 3){
                                  lodimagep(3);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 4){
                                  lodimagep(4);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 5){
                                  lodimagep(5);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 6){
                                  lodimagep(6);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 7){
                                  lodimagep(7);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 8){
                                  lodimagep(8);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 9){
                                  lodimagep(9);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 10){
                                  lodimagep(10);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 11){
                                  lodimagep(11);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 12){
                                  lodimagep(12);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 13){
                                  lodimagep(13);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 14){
                                  lodimagep(14);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 15){
                                  lodimagep(15);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 16){
                                  lodimagep(16);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 17){
                                  lodimagep(17);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 18){
                                  lodimagep(18);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 19){
                                  lodimagep(19);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 20){
                                  lodimagep(20);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 21){
                                  lodimagep(21);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 22){
                                  lodimagep(22);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 23){
                                  lodimagep(23);
                              }
                              else if (y2 <= igvy + (int) (arrdown.getHeight() * scaleHeight) / 24 * 24){
                                  lodimagep(24);    //加载最后一张图片时, 将在lodmigep() 方法中调用书写完成对话框
                              }

                              else {
                                  type = 0;  //手指离开,设置书写关闭
                              }
                         }
                      }
                      break;
                 case MotionEvent.ACTION_UP:      //手势抬起判断
                     type = 0 ;  //手势关闭
                     //当手指离开时
                     if (touchTimer != null) { //判断计时器是否为空
                         touchTimer.cancel();   //中断计时器
                         touchTimer = null;     //设置计时器为空
                     }

                     touchTimer = new Timer(); //初始化计时器
                     touchTimer.schedule(new TimerTask() {
                         @Override
                         public void run() {
                             Thread thread = new Thread(new Runnable() {
                                 @Override
                                 public void run() {
                                     Message message = new Message();
                                     message.what = 2; //发送的消息为2
                                     mHandler.sendMessage(message);
                                 }
                             });
                             thread.start();
                         }
                     }, 300,200);
             }//获取行动方式尾部

             return true;
         }
     });


 }  //iniView() 方法尾部

    //递减显示帧图片 handler消息头部
    public Handler mHandler = new Handler(){
     public  void handleMessage(Message msg){
         switch (msg.what){
             case 2:          //接收到手势抬起子线程消息时
                 jlodimage();  //调用资源图片倒退显示
                 break;
                 default:
                     break;
         }
         super.handleMessage(msg);
     }
    };

    private void jlodimage() {
        if (i == 25) {
        } else if (i < 25) {
            if (i > 1) {
                i--;
            }else  if (i == 1) {
                i = 1;
                if (touchTimer != null){
                    touchTimer.cancel();
                    touchTimer = null;
                }
            }

            String name = "on1_" + i; //图片名称
            int imgid =  getResources().getIdentifier(name, "drawable", "com.yuyang.writenumber");
            iv_frame.setBackgroundResource(imgid);
        }

    }

    private  synchronized void lodimagep(int j) {
     i = j;             //当前图片位置
     if ( i < 25) {        //如果图片位置小于25
      String name = "on1_" + i;  //当前图片名称
      //获取图片资源id
      int imgid = getResources().getIdentifier(name, "drawable", "com.yuyang.writenumber");
      iv_frame.setBackgroundResource(imgid);  //设置背景图片
      i++;
     }

     if ( j == 24) {     //如果当前图片位置为24
      if (typedialog) {   //没有对话框的情况下
       dialog();        //调用书写完成对话框方法
      }
     }
 }

 private void dialog() {   //完成后提示对话框头部
  typedialog = false;      //修改对话框状态
  //实例化对话框
  AlertDialog.Builder builder = new AlertDialog.Builder(OneActivity.this);
  builder.setMessage("太棒了! 书写完全正确!");
  builder.setTitle("提示");

  //设置对话框完成按钮单击事件头部
  builder.setPositiveButton("完成", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();     //dialog 消失
    typedialog = true;    //修改对话框状态
    finish();        //关闭当前页面

   }
  });              //对话框完成按钮单击事件尾部

  //设置对话框再来一次按钮单击事件头部
   builder.setNegativeButton("什么? 再来一次", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
     dialog.dismiss();
     typedialog = true;  //修改对话框状态
     i = 1;
     lodimagep(1);  //调用加载图片方法中的第一张图片
    }
   });
   builder.create().show();  //创建并显示对话框

 }

} //OneActivity类的尾部

  在活动中设置所需的 全局对象及变量, 主要用于声明手势事件中手指按下的坐标、 图片的缩放比例、 显示写数字的ImageView  控件。 

  在onCreate() 方法中有两个操作 一个是背景音乐的控制, 不在赘述, 另一个方法initView() 为界面的初始化。获取外层布局以及书写区域的子布局, 并给子布局注册触摸事件监听器,根据手指按下时的坐标 来决定是否开启书写, 如果开启书写 则触发逐帧动画 根据手指在屏幕上移动的坐标变化 加载不同的资源图片,

   lodimagep() 方法是加载图片, 调用Resource 的 getIdentifier() 方法 获取图片资源的id,通过setBackgroundResource() 将对应图片设置为布局背景。 当图片id 为24时 即逐帧动画的最后一张, 此时调用对话框 让用户 决定是否再来一次, 或者点击完成 关闭当前页面; 当用户选择再来一次时, 关闭对话框, 将对话框状态设置为true ,并在当前页面重新加载第一帧图片, 加载完成后 书写区域已近设置好了触摸监听, 满足用户的再次游戏。

    接下来来看一下 当用户未完成书写图片倒退显示的功能, 此处用到了安卓的异步消息处理只是, 当用户手指抬起后 当计时器 为空后 再次初始化一个计时器 和定时任务,并在定时任务中 开启子线程 调用Handler 发送新创建的Message 消息,Message 的字段为2. 当Handeler 接收到子线程发送的消息后 ,会触发 Handler 中的 jlodimage() 方法, 以此来实现 资源图片倒退的效果。 

   在jlodimage() 方法中, 当图片id逐渐减小至1 时, 需要将定时器 置为空, 停止计时。

  接着看一下最后一个模块, “演示动画框设计”, 

5、mCustomProgressDialog 工具类 + 布局

   
 <!--相对布局头部-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#333333"
    >

    <!--演示书写规范-->
    <ImageView
        android:id="@+id/loadingIv"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <!--显示提示性文字-->
    <TextView
        android:id="@+id/loadingTv"
        android:layout_centerHorizontal="true"
        android:textSize="10sp"
        android:textColor="#FFFFFF"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <!--相对布局尾部-->
</RelativeLayout>
  最外层为相对布局, 并将背景设置为灰色,在布局中添加 ImageView 和 TextView 两个控件。接着看工具类的实现。

public class mCustomProgressDialog extends ProgressDialog {   //自定义对话框类头部

    private AnimationDrawable mAnimation; //设置对话框对话资源
    private Context mContext;  //设置对话框上下文
    private ImageView mImageView;  //设置对话框背景图片
    private String mLoadingTip;  //设置对话框文字
    private TextView mLoadingTv;  //显示对话框文字
    private int mResid;  //设置动画资源的id

    //自定义对话框构造方法头部
    public mCustomProgressDialog(Context context, String content, int id) {
        super(context);
        this.mContext = context;    //为上下文赋值
        this.mLoadingTip = content;
        this.mResid = id;

        //设置单击周边是否让dialog 消失, 设置为true, 单击周边消失
        setCanceledOnTouchOutside(true);

    }//自定义对话框构造方法尾部

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progress_dialog);

        mLoadingTv = (TextView) findViewById(R.id.loadingTv);
        mImageView = (ImageView) findViewById(R.id.loadingIv);

        if (mResid == 0){    //当动画资源id 为0时
            mImageView.setBackgroundDrawable(null); //设置背景为空
        } else {
            mImageView.setBackgroundResource(mResid);  //设置指定动画资源id
        }

        //通过Imageview 对象拿到背景显示的动画资源文件
        mAnimation = (AnimationDrawable) mImageView.getBackground();
        //为了防止在onCreate 方法中只显示第一帧的解决方案之一
        mImageView.post(new Runnable() {
            @Override
            public void run() {
                //动画开始
                mAnimation.start();
            }
        });
        mLoadingTv.setText(mLoadingTip);
    }


  }//自定义对话框类尾部
   在OneActivity 的 OnYS 单击事件中调用的工具类构造方法, 此构造方法的第三个参数为 逐帧动画:

public void OnYS(View v){   //创建演示按钮, 单击事件头部
        if (mdialog == null){
            mdialog = new mCustomProgressDialog(this, "演示中单击边缘取消", R.drawable.frame1);
        }
        mdialog.show();    //显示对话框
    }


<!--逐帧动画头部-->
<animation-list
    android:oneshot="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/on1_1" android:duration="150"/>
    <item android:drawable="@drawable/on1_2" android:duration="150"/>
    <item android:drawable="@drawable/on1_3" android:duration="150"/>
    <item android:drawable="@drawable/on1_4" android:duration="150"/>
    <item android:drawable="@drawable/on1_5" android:duration="150"/>
    <item android:drawable="@drawable/on1_6" android:duration="150"/>
    <item android:drawable="@drawable/on1_7" android:duration="150"/>
    <item android:drawable="@drawable/on1_8" android:duration="150"/>
    <item android:drawable="@drawable/on1_9" android:duration="150"/>
    <item android:drawable="@drawable/on1_10" android:duration="150"/>
    <item android:drawable="@drawable/on1_11" android:duration="150"/>
    <item android:drawable="@drawable/on1_12" android:duration="150"/>
    <item android:drawable="@drawable/on1_13" android:duration="150"/>
    <item android:drawable="@drawable/on1_14" android:duration="150"/>
    <item android:drawable="@drawable/on1_15" android:duration="150"/>
    <item android:drawable="@drawable/on1_16" android:duration="150"/>
    <item android:drawable="@drawable/on1_17" android:duration="150"/>
    <item android:drawable="@drawable/on1_18" android:duration="150"/>
    <item android:drawable="@drawable/on1_19" android:duration="150"/>
    <item android:drawable="@drawable/on1_20" android:duration="150"/>
    <item android:drawable="@drawable/on1_21" android:duration="150"/>
    <item android:drawable="@drawable/on1_22" android:duration="150"/>
    <item android:drawable="@drawable/on1_23" android:duration="150"/>
    <item android:drawable="@drawable/on1_24" android:duration="150"/>
    <!--逐帧动画尾部-->
</animation-list>
    逐帧动画的图片帧率为0.15秒, 即每隔0.15秒, 自动切换下一帧的资源图片id。
 将mCustomProgressDialog 工具类继承 ProgressDialog 类, 在类中创建构造方法, 在构造方法中设置需要传递的“id”, 与文字, 最后设置对话框单击事件,借助setCanceledOnTouchOutside(true), 实现单击对话框周边时关闭当前当前对话框。在对话框中创建AnimationDrawable 动画画板 通过ImageView 对象拿到背景的动画资源文件,并在ImageView
 的post() 方法中开启线程 完成演示动画。 



  




   






猜你喜欢

转载自blog.csdn.net/qq_41405257/article/details/80313872