Android实现疯狂连连看游戏之加载界面图片和实现游戏Activity(四)

正如在《我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)》一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piece对象时,程序会直接调用ImageUtil的getPlayImages()方法去获取图片,该方法会随机从res/drawable目录中取得N张图片。

下面是res/drawable目录视图:

为了让getPlayImages()方法能随机从res/drawable目录中取得N张图片,具体实现分为以下几步:

  • 通过反射来获取R.drawable的所有Field(Android的每张图片资源都会自动转换为R.drawable的静态Field),并将这些Field值添加到一个List集合中。
  • 从第一步得到的List集合中随机“抽取”N/2个图片ID。
  • 将第二步得到的N/2个图片ID全部复制一份,这样就得到了N个图片ID,而且每个图片ID都可以找到与之配对的。
  • 将第三步得到的N个图片ID再次“随机打乱”,并根据图片ID加载相应的Bitmap对象,最后把图片ID及对应的Bitmap封装成PieceImage对象后返回。

下面是ImageUtil类的代码:cn\oyp\link\utils\ImageUtil.java

package cn.oyp.link.utils; 

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import cn.oyp.link.R;
import cn.oyp.link.view.PieceImage; 

/**
 * 图片资源工具类, 主要用于读取游戏图片资源值<br/>
 * <br/>
 * 关于本代码介绍可以参考一下博客: <a href="http://blog.csdn.net/ouyang_peng" rel="external nofollow" rel="external nofollow" >欧阳鹏的CSDN博客</a> <br/>
 */
public class ImageUtil {
 /**
  * 保存所有连连看图片资源值(int类型)
  */
 private static List<Integer> imageValues = getImageValues(); 

 /**
  * 获取连连看所有图片的ID(约定所有图片ID以p_开头)
  */
 public static List<Integer> getImageValues() {
  try {
   // 得到R.drawable所有的属性, 即获取drawable目录下的所有图片
   Field[] drawableFields = R.drawable.class.getFields();
   List<Integer> resourceValues = new ArrayList<Integer>();
   for (Field field : drawableFields) {
    // 如果该Field的名称以p_开头
    if (field.getName().indexOf("p_") != -1) {
     resourceValues.add(field.getInt(R.drawable.class));
    }
   }
   return resourceValues;
  } catch (Exception e) {
   return null;
  }
 } 

 /**
  * 随机从sourceValues的集合中获取size个图片ID, 返回结果为图片ID的集合
  *
  * @param sourceValues
  *   从中获取的集合
  * @param size
  *   需要获取的个数
  * @return size个图片ID的集合
  */
 public static List<Integer> getRandomValues(List<Integer> sourceValues,
   int size) {
  // 创建一个随机数生成器
  Random random = new Random();
  // 创建结果集合
  List<Integer> result = new ArrayList<Integer>();
  for (int i = 0; i < size; i++) {
   try {
    // 随机获取一个数字,大于、小于sourceValues.size()的数值
    int index = random.nextInt(sourceValues.size());
    // 从图片ID集合中获取该图片对象
    Integer image = sourceValues.get(index);
    // 添加到结果集中
    result.add(image);
   } catch (IndexOutOfBoundsException e) {
    return result;
   }
  }
  return result;
 } 

 /**
  * 从drawable目录中中获取size个图片资源ID(以p_为前缀的资源名称), 其中size为游戏数量
  *
  * @param size
  *   需要获取的图片ID的数量
  * @return size个图片ID的集合
  */
 public static List<Integer> getPlayValues(int size) {
  if (size % 2 != 0) {
   // 如果该数除2有余数,将size加1
   size += 1;
  }
  // 再从所有的图片值中随机获取size的一半数量,即N/2张图片
  List<Integer> playImageValues = getRandomValues(imageValues, size / 2);
  // 将playImageValues集合的元素增加一倍(保证所有图片都有与之配对的图片),即N张图片
  playImageValues.addAll(playImageValues);
  // 将所有图片ID随机“洗牌”
  Collections.shuffle(playImageValues);
  return playImageValues;
 } 

 /**
  * 将图片ID集合转换PieceImage对象集合,PieceImage封装了图片ID与图片本身
  *
  * @param context
  * @param resourceValues
  * @return size个PieceImage对象的集合
  */
 public static List<PieceImage> getPlayImages(Context context, int size) {
  // 获取图片ID组成的集合
  List<Integer> resourceValues = getPlayValues(size);
  List<PieceImage> result = new ArrayList<PieceImage>();
  // 遍历每个图片ID
  for (Integer value : resourceValues) {
   // 加载图片
   Bitmap bm = BitmapFactory.decodeResource(context.getResources(),
     value);
   // 封装图片ID与图片本身
   PieceImage pieceImage = new PieceImage(bm, value);
   result.add(pieceImage);
  }
  return result;
 } 

 /**
  * 获取选中标识的图片
  * @param context
  * @return 选中标识的图片
  */
 public static Bitmap getSelectImage(Context context) {
  Bitmap bm = BitmapFactory.decodeResource(context.getResources(),
    R.drawable.selected);
  return bm;
 }
}

前面已经给出了游戏界面的布局文件,该布局文件需要一个Activity来负责显示,除此之外,Activity还需要为游戏界面的按钮、GameView组件的事件提供事件监听器。
尤其是对于GameView组件,程序需要监听用户的触摸动作,当用户触摸屏幕时,程序需要获取用户触摸的是哪个方块,并判断是否需要“消除”该方块。为了判断是否消除该方块,程序需要进行如下判断:

如果程序之前已经选择了某个方块,就判断当前触碰的方块是否能和之前的方块“相连”,如果可以相连,则消除两个方块;如果不能相连,则把当前方块设置为选中方块。

如果程序之前没有选中方块,直接将当前方块设置为选中方块。

下面是Activity的代码:cn\oyp\link\LinkActivity.java

package cn.oyp.link; 

import java.util.Timer;
import java.util.TimerTask; 

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import cn.oyp.link.board.GameService;
import cn.oyp.link.board.impl.GameServiceImpl;
import cn.oyp.link.utils.GameConf;
import cn.oyp.link.utils.LinkInfo;
import cn.oyp.link.view.GameView;
import cn.oyp.link.view.Piece; 

/**
 * 游戏Activity <br/>
 * <br/>
 * 关于本代码介绍可以参考一下博客: <a href="http://blog.csdn.net/ouyang_peng" rel="external nofollow" rel="external nofollow" >欧阳鹏的CSDN博客</a> <br/>
 */
public class LinkActivity extends Activity {
 /**
  * 游戏配置对象
  */
 private GameConf config;
 /**
  * 游戏业务逻辑接口
  */
 private GameService gameService;
 /**
  * 游戏界面
  */
 private GameView gameView;
 /**
  * 开始按钮
  */
 private Button startButton;
 /**
  * 记录剩余时间的TextView
  */
 private TextView timeTextView;
 /**
  * 失败后弹出的对话框
  */
 private AlertDialog.Builder lostDialog;
 /**
  * 游戏胜利后的对话框
  */
 private AlertDialog.Builder successDialog;
 /**
  * 定时器
  */
 private Timer timer = new Timer();
 /**
  * 记录游戏的剩余时间
  */
 private int gameTime;
 /**
  * 记录是否处于游戏状态
  */
 private boolean isPlaying;
 /**
  * 振动处理类
  */
 private Vibrator vibrator;
 /**
  * 记录已经选中的方块
  */
 private Piece selectedPiece = null;
 /**
  * Handler类,异步处理
  */
 private Handler handler = new Handler() {
  public void handleMessage(Message msg) {
   switch (msg.what) {
   case 0x123:
    timeTextView.setText("剩余时间: " + gameTime);
    gameTime--; // 游戏剩余时间减少
    // 时间小于0, 游戏失败
    if (gameTime < 0) {
     // 停止计时
     stopTimer();
     // 更改游戏的状态
     isPlaying = false;
     // 失败后弹出对话框
     lostDialog.show();
     return;
    }
    break;
   }
  }
 }; 

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  // 初始化界面
  init();
 } 

 /**
  * 初始化游戏的方法
  */
 private void init() {
  config = new GameConf(8, 9, 2, 10, GameConf.DEFAULT_TIME, this);
  // 得到游戏区域对象
  gameView = (GameView) findViewById(R.id.gameView);
  // 获取显示剩余时间的文本框
  timeTextView = (TextView) findViewById(R.id.timeText);
  // 获取开始按钮
  startButton = (Button) this.findViewById(R.id.startButton);
  // 获取振动器
  vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
  // 初始化游戏业务逻辑接口
  gameService = new GameServiceImpl(this.config);
  // 设置游戏逻辑的实现类
  gameView.setGameService(gameService);
  // 为开始按钮的单击事件绑定事件监听器
  startButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View source) {
    startGame(GameConf.DEFAULT_TIME);
   }
  });
  // 为游戏区域的触碰事件绑定监听器
  this.gameView.setOnTouchListener(new View.OnTouchListener() {
   public boolean onTouch(View view, MotionEvent e) {
    if (e.getAction() == MotionEvent.ACTION_DOWN) {
     gameViewTouchDown(e);
    }
    if (e.getAction() == MotionEvent.ACTION_UP) {
     gameViewTouchUp(e);
    }
    return true;
   }
  });
  // 初始化游戏失败的对话框
  lostDialog = createDialog("Lost", "游戏失败! 重新开始", R.drawable.lost)
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
      startGame(GameConf.DEFAULT_TIME);
     }
    });
  // 初始化游戏胜利的对话框
  successDialog = createDialog("Success", "游戏胜利! 重新开始",
    R.drawable.success).setPositiveButton("确定",
    new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
      startGame(GameConf.DEFAULT_TIME);
     }
    });
 } 

 @Override
 protected void onPause() {
  // 暂停游戏
  stopTimer();
  super.onPause();
 } 

 @Override
 protected void onResume() {
  // 如果处于游戏状态中
  if (isPlaying) {
   // 以剩余时间重新开始游戏
   startGame(gameTime);
  }
  super.onResume();
 } 

 /**
  * 触碰游戏区域的处理方法
  *
  * @param event
  */
 private void gameViewTouchDown(MotionEvent event) {
  // 获取GameServiceImpl中的Piece[][]数组
  Piece[][] pieces = gameService.getPieces();
  // 获取用户点击的x座标
  float touchX = event.getX();
  // 获取用户点击的y座标
  float touchY = event.getY();
  // 根据用户触碰的座标得到对应的Piece对象
  Piece currentPiece = gameService.findPiece(touchX, touchY);
  // 如果没有选中任何Piece对象(即鼠标点击的地方没有图片), 不再往下执行
  if (currentPiece == null)
   return;
  // 将gameView中的选中方块设为当前方块
  this.gameView.setSelectedPiece(currentPiece);
  // 表示之前没有选中任何一个Piece
  if (this.selectedPiece == null) {
   // 将当前方块设为已选中的方块, 重新将GamePanel绘制, 并不再往下执行
   this.selectedPiece = currentPiece;
   this.gameView.postInvalidate();
   return;
  }
  // 表示之前已经选择了一个
  if (this.selectedPiece != null) {
   // 在这里就要对currentPiece和prePiece进行判断并进行连接
   LinkInfo linkInfo = this.gameService.link(this.selectedPiece,
     currentPiece);
   // 两个Piece不可连, linkInfo为null
   if (linkInfo == null) {
    // 如果连接不成功, 将当前方块设为选中方块
    this.selectedPiece = currentPiece;
    this.gameView.postInvalidate();
   } else {
    // 处理成功连接
    handleSuccessLink(linkInfo, this.selectedPiece, currentPiece,
      pieces);
   }
  }
 } 

 /**
  * 触碰游戏区域的处理方法
  *
  * @param e
  */
 private void gameViewTouchUp(MotionEvent e) {
  this.gameView.postInvalidate();
 } 

 /**
  * 以gameTime作为剩余时间开始或恢复游戏
  *
  * @param gameTime
  *   剩余时间
  */
 private void startGame(int gameTime) {
  // 如果之前的timer还未取消,取消timer
  if (this.timer != null) {
   stopTimer();
  }
  // 重新设置游戏时间
  this.gameTime = gameTime;
  // 如果游戏剩余时间与总游戏时间相等,即为重新开始新游戏
  if (gameTime == GameConf.DEFAULT_TIME) {
   // 开始新的游戏游戏
   gameView.startGame();
  }
  isPlaying = true;
  this.timer = new Timer();
  // 启动计时器 , 每隔1秒发送一次消息
  this.timer.schedule(new TimerTask() {
   public void run() {
    handler.sendEmptyMessage(0x123);
   }
  }, 0, 1000);
  // 将选中方块设为null。
  this.selectedPiece = null;
 } 

 /**
  * 成功连接后处理
  *
  * @param linkInfo
  *   连接信息
  * @param prePiece
  *   前一个选中方块
  * @param currentPiece
  *   当前选择方块
  * @param pieces
  *   系统中还剩的全部方块
  */
 private void handleSuccessLink(LinkInfo linkInfo, Piece prePiece,
   Piece currentPiece, Piece[][] pieces) {
  // 它们可以相连, 让GamePanel处理LinkInfo
  this.gameView.setLinkInfo(linkInfo);
  // 将gameView中的选中方块设为null
  this.gameView.setSelectedPiece(null);
  this.gameView.postInvalidate();
  // 将两个Piece对象从数组中删除
  pieces[prePiece.getIndexX()][prePiece.getIndexY()] = null;
  pieces[currentPiece.getIndexX()][currentPiece.getIndexY()] = null;
  // 将选中的方块设置null。
  this.selectedPiece = null;
  // 手机振动(100毫秒)
  this.vibrator.vibrate(100);
  // 判断是否还有剩下的方块, 如果没有, 游戏胜利
  if (!this.gameService.hasPieces()) {
   // 游戏胜利
   this.successDialog.show();
   // 停止定时器
   stopTimer();
   // 更改游戏状态
   isPlaying = false;
  }
 } 

 /**
  * 创建对话框的工具方法
  *
  * @param title
  *   标题
  * @param message
  *   内容
  * @param imageResource
  *   图片
  * @return
  */
 private AlertDialog.Builder createDialog(String title, String message,
   int imageResource) {
  return new AlertDialog.Builder(this).setTitle(title)
    .setMessage(message).setIcon(imageResource);
 } 

 /**
  * 停止计时
  */
 private void stopTimer() {
  // 停止定时器
  this.timer.cancel();
  this.timer = null;
 }
}

该Activity用了两个类,这两个类在下一篇博客中再进行相关描述。
GameConf:负责管理游戏的初始化设置信息。
GameService:负责游戏的逻辑实现。

关于具体的实现步骤,请参考下面的链接:

我的Android进阶之旅------>Android疯狂连连看游戏的实现之游戏效果预览(一)

我的Android进阶之旅------>Android疯狂连连看游戏的实现之开发游戏界面(二)

我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)

我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android通过自定义Activity实现悬浮的Dialog详解

    前言 其实实现悬浮的自定义窗体有很多方法,自定义Dialog,自定义layout 均可以实现.自定义activity也是可以的,今天我就介绍一下activity的实现方法.下面来看看详细的介绍: 效果图 如图可以看出,当前的窗体,第一眼其实和dialog没有什么区别,但是它是自定义activity实现.如何实现的呢? 代码如下: 新建activity @Override protected void onCreate(Bundle savedInstanceState) { super.onCr

  • Android activity和view判断滑动

    Android activity和view判断滑动 实例代码: //手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2) float x1 = 0; float x2 = 0; float y1 = 0; float y2 = 0; @Override public boolean onTouchEvent(MotionEvent event) { //继承了Activity的onTouchEvent方法,直接监听点击事件 if(event.getAction() == Motion

  • 详解Android Activity之间跳转出现短暂黑屏的处理方法

    摘要: 如何解决页面之间跳转时的黑屏问题呢? 在默认情况下,Android应用程序启动时,会有一个黑屏的时期.原因是,首个activity会加载一些数据,比如初始化列表数据.向服务器发送请求获取数据等等.同样,使用startActivity(intent)方法从一个Activity进入到新的Activity时,这个过程中也会出现短暂的黑屏.这个问题的存在是由Android应用框架决定的,但的确很影响用户体验.下面就动手来解决这个黑屏 问题! 第一步:自定义Theme(主题) 在your_proj

  • Android Activity进出动画三种方法

     Android Activity进出动画三种方法 实现activity的进出场动画总共有3种方式,下面会一一列出,首先给出示例的动画xml文件. 动画的xml文件 <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromYDelta="

  • Android 中自定义Dialog样式的Activity点击空白处隐藏软键盘功能(dialog不消失)

    一.需求触发场景: 项目中需要开发带有EditText的Dialog显示,要求在编辑完EditText时,点击Dilog的空白处隐藏软键盘.但是Dialog不会消失.示例如下: 二.实现方法: 发布需求时,我个人曾想过直接通过new的方式直接创建Dialog,经过多次尝试,无法实现要求,所以采用将Activity设置为Dialog样式进行展示,调用方法实现需求.具体实现如下: 本次演示示例的工程结构: 2.1AndroidMainfest.xml配置文件 需要在配置文件中将需要显示为dialog

  • Android DaggerActivityComponent错误解决办法详解

    Android DaggerActivityComponent错误解决办法详解 在使用dagger2的过程中,如果修改了某个类的内容,第一次编译运行时总会报错:错误: 找不到符号 符号: 类 DaggerActivityComponent 位置: 程序包 com--的错误,然后再重新编译一次,才会正常运行,经过仔细的检查终于找到问题的根源: 错误的原因是build.gradle(Module:app)引入'com.google.dagger:dagger-compiler:2.0.2'使用的是c

  • 关于Android中点击通知栏的通知启动Activity问题解决

    前言 最近遇到一个很奇葩的问题,终于解决了,所以想着记录一下,方便大家或者自己以后有需要的时候可以参考学习. 问题场景 用小米手机使用小米推送一条消息,然后点击通知栏中的消息启动应用,然后进入会话的Activity.应用启动后,如果当前界面不是会话界面,那么新消息会在通知栏显示消息提醒,然后点击会话消息后却进不了会话的Activity,即点击了通知栏通知后,系统都没有启动指定Activity的意思,没有看到系统启动Activity的Log,到是会看到系统处理这个Activity的影子. 这个指定

  • Android中Activity滑动关闭的效果

    最近感觉有一个Activity关闭的效果挺不错的,就是手势滑动就可以关闭当前Activity,于是就想写一篇博客和大家一起分享下!废话不多说,老规矩,还先上效果图,更直观! 项目地址:https://github.com/xinyitiandi/SlidingFinishDemo 上代码: 1.第一个Activity: package com.ekeguan.slidingfinishdemo; import android.content.Intent; import android.os.B

  • Android实现疯狂连连看游戏之加载界面图片和实现游戏Activity(四)

    正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piece对象时,程序会直接调用ImageUtil的getPlayImages()方法去获取图片,该方法会随机从res/drawable目录中取得N张图片. 下面是res/drawable目录视图: 为了让getPlayImages()方法能随机从res/drawable目录中取得N张图片,具体实现分为以下几步: 通

  • Android圆形头像拍照后“无法加载此图片”的问题解决方法(适配Android7.0)

    Feature: 点击选择拍照或者打开相册,选取图片进行裁剪最后设置为圆形头像. Problem: 拍好照片,点击裁剪,弹Toast"无法加载此图片". Solution: 在裁剪的class里加两行代码 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 主要代码如下: public static final S

  • Android使用View Animation实现动画加载界面

    之前分别介绍了View Animation和Drawable Animation,学了就要用啊,今天给大家一个使用View Animation实现动画加载界面的实现. 首先先看一下实现效果. 下面是实现代码 package com.example.animationloading; import java.util.Timer; import java.util.TimerTask; import android.annotation.SuppressLint; import android.a

  • Android实现疯狂连连看游戏之开发游戏界面(二)

    连连看的游戏界面十分简单,大致可以分为两个区域: --游戏主界面区 --控制按钮和数据显示区 1.开发界面布局 本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定义组件,下面是一个水平排列的LinearLayout. 下面是本程序的布局文件:/res/layout/main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andr

  • Android实现疯狂连连看游戏之状态数据模型(三)

    对于游戏玩家而言,游戏界面上看到的"元素"千变万化:但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已.因此建立游戏的状态数据模型是实现游戏逻辑的重要步骤. 1.定义数据模型 连连看的界面是一个NxM的"网格",每个网格上显示一张图片.而这个网格只需要一个二维数组来定义即可,而每个网格上所显示的图片,对于底层数据模型来说,不同的图片对于着不同的数值即可. 对于上图所示的数据模型,只要让数值为0的网格上不绘制图片,其他数值的网

  • Android实现疯狂连连看游戏之实现游戏逻辑(五)

    在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的初始化设置信息. GameService:负责游戏的逻辑实现. 其中GameConf的代码如下:cn\oyp\link\utils\GameConf.java package cn.oyp.link.utils; import android.content.Context; /** * 保存游戏配置的对象

  • Android实现疯狂连连看游戏之游戏效果预览(一)

    今天看完了李刚老师的<疯狂Android讲义>一书中的第18章<疯狂连连看>,从而学会了如何编写一个简单的Android疯狂连连看游戏. 开发这个流行的小游戏,难度适中,而且能充分激发学习热情,适合Android初学者来说是一个不错的选择.对于该游戏的开发,需要重点掌握单机游戏的界面分析和数据建模能力:游戏玩家严重看到的是游戏界面,但是在开发者眼中看到的应该是数据模型.除此之外,单机游戏通常需要一个比较美观的界面,需要通过自定义View来实现游戏主界面. 开发连连看游戏除了需要理解

  • Android实现加载广告图片和倒计时的开屏布局

    这是一个android开屏布局的实例,可以用于加载广告图片和倒计时的布局.程序中设置的LayoutParams,划分额外空间比例为6分之5,具体权重比例可根据用户自己需求来自定义,异步加载广告图片,相关的Android代码. 具体实现代码如下: package cn.waps.extend; import android.app.Activity; import android.content.Context; import android.content.res.Configuration;

  • Android插件化之资源动态加载

    Android插件化之资源动态加载 一.概述 Android插件化的一个重要问题就是插件资源访问问题,先列出会面对的问题 1.如何加载插件资源 2.如何处理插件资源与宿主资源的处突:插件化资源问题要做到的效果是,如果我们要获取的资源在插件中找得到,则加载优先加载插件的,如果找不到,则到宿主资源中找.这样能做到动态更新的效果. 3.如何确保插件和宿主使用到的是被修改过的资源. 二.原理分析 在做一件事之前必须先弄清楚原理,所以,这里先要弄清楚Android的资源体系原理. 1.资源链 Contex

  • Android自定义view实现阻尼效果的加载动画

    效果: 需要知识: 1. 二次贝塞尔曲线 2. 动画知识 3. 基础自定义view知识 先来解释下什么叫阻尼运动 阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动.衰减振动.[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来.这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运

随机推荐