春节期间,摇一摇抢红包很好的推广了微信摇一摇功能。
现在我们来实现一个摇一摇抢优惠券的功能。
需求概述
用户登录之后才能参加活动。
进入活动之后,每人每天有三次摇一摇机会。
根据服务器返回的中奖结果显示不同的对话框。
大概如图:
界面实现
我们根据设计给出的资源,先把活动涉及到的几个界面给画出来。
主界面:
tips:
dialog:
功能实现
核心功能其实很简单,就是根据传感器返回的数据来判断用户是否在摇手机,然后根据相应的情况进行处理。
还要加上一个摇一摇的动画。
传感器的使用
注册传感器:
private SensorManager sensor;
sensor = (SensorManager) this.getSystemService(Service.SENSOR_SERVICE);
sensor.registerListener(shakelistener,
sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
sensor.unregisterListener(shakelistener);//解除监听
监听器:
public class ShakeListenerUtils implements SensorEventListener
{
public ShakeListenerUtils()
{
super();
}
@SuppressLint("ShowToast")
@Override
public void onSensorChanged(SensorEvent event)
{
int sensorType = event.sensor.getType();
if (sensorType == Sensor.TYPE_ACCELEROMETER)
{
//values[0]:X轴,values[1]:Y轴,values[2]:Z轴
float[] values = event.values;
/*正常情况下,任意轴数值最大就在9.8~10之间,只有在突然摇动手机
的时候,瞬时加速度才会突然增大或减少。监听任一轴的加速度大于19即可
*/
if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15 || Math
.abs(values[2]) > 15))
{
startAnim ();
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
//当传感器精度改变时回调该方法,Do nothing.
}
}
添加动画和震动
自定义动画:
public void startAnim () { //定义摇一摇动画动画
AnimationSet animup = new AnimationSet(true);
CustomerAnimation customerAnimation=new CustomerAnimation();
customerAnimation.setDuration(1000);
customerAnimation.setAnimationListener(this);
animup.addAnimation(customerAnimation);
handImageView.startAnimation(animup);
}
class CustomerAnimation extends Animation {
private int mWaveTimes=5;//摇摆次数
private int mWaveRange=50;//摇摆幅度
public CustomerAnimation(){
}
public CustomerAnimation(int waveTimes,int waveRange){
mWaveTimes = waveTimes;
mWaveRange = waveRange;
}
@Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
//运用周期性函数,实现左右摇摆
t.getMatrix().setTranslate((int)(Math.sin(interpolatedTime*Math.PI*mWaveTimes)*mWaveRange),0);
}
}
添加震动
震动我们就加在动画开始的部分吧。
让活动继承
AnimationListener
接口,然后分别实现
onAnimationStart
onAnimationEnd
onAnimationRepeat
于是我们只要这样做就行了:
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
vibrator.vibrate(200);
// 系统提示音
// Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
// Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
// r.play();
}
震动两秒,一行代码就够了。
对了别忘了注册vibrator:
private Vibrator vibrator;
vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
其实我们也可以在这个发出个声音,我直接调用了系统的提示音,去掉注释就能用了。
添加dialog
在动画结束的时候,我们弹出对话框。
并且根据情况设置不同的文字。
初始化dialog
private AlertDialog alertDialog;
private Builder builder;
builder=new Builder(ShakeActivity.this);
alertDialog=new Builder(this).create();
重写onAnimationEnd()
@Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
alertDialog.setCancelable(false);
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
Window window=alertDialog.getWindow();
window.setContentView(R.layout.dialog_view);
shake_pop_face=(ImageView) window.findViewById(R.id.shake_pop_face1);
dialog_textView=(TextView) window.findViewById(R.id.dialog_textView);
dialog_button=(Button) window.findViewById(R.id.dialog_button);
dialog_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
alertDialog.dismiss();
sensor.registerListener(shakelistener,
sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
});
sensor.unregisterListener(shakelistener);
ArrayList<String> failure1=new ArrayList<String>();
failure1.add("不信邪?再来一次");
failure1.add("慢点“我晕”,再试一次");
failure1.add("换一只手,试一试");
failure1.add("别气馁,好运还在后头");
failure1.add("死了都要摇,再来一次");
failure1.add("摇劲不够,再猛烈一些");
ArrayList<String> failure2=new ArrayList<String>();
failure2.add("哭了,小编你个坑货!明天再来吧");
failure2.add("多做好事积攒RP,明天再来吧!");
failure2.add("再摇,再努力!明天继续");
failure2.add("至少还有明天~~");
failure2.add("生命不息,摇奖不止");
ArrayList<String> success=new ArrayList<String>();
success.add("摇劲足矣,5元给您!快去“我的优惠券”查看吧");
success.add("运气来了,挡也挡不住!5元给您!");
success.add("哟,恭喜得5元“票”子,快去“我的优惠券”查看");
//中奖的情况
if (shakeCounts>0&&checkBoxWin.isChecked()) {
shakeCounts--;
shakeTimesTextView.setText("今天您还可以摇"+shakeCounts+"次");
if (isWon) {
//已经中过奖了,但是次数未用完
dialog_textView.setText("亲,留点机会给别人吧!");
dialog_button.setText("知道了");
shake_pop_face.setImageResource(R.drawable.shake_pop_face5);
} else {
isWon=true;
dialog_textView.setText(success.get(
(int) ((Math.random()*100)%success.size())
));
}
return;
}
//没中奖的情况
if (shakeCounts>0&&!checkBoxWin.isChecked()) {
shakeCounts--;
shakeTimesTextView.setText("今天您还可以摇"+shakeCounts+"次");
if (shakeCounts==0) {
//三次全没中
dialog_textView.setText(failure2.get(
(int) ((Math.random()*100)%failure2.size())
));
dialog_button.setText("明天再来吧");
shake_pop_face.setImageResource(R.drawable.shake_pop_face3);
} else {
dialog_textView.setText(failure1.get(
(int) ((Math.random()*100)%failure1.size())
));
dialog_button.setText("再来一次");
shake_pop_face.setImageResource(R.drawable.shake_pop_face2);
}
return;
}
//次数用完
if (shakeCounts<=0){
dialog_textView.setText("亲,每天只有三次机会哦~");
dialog_button.setText("知道了");
shake_pop_face.setImageResource(R.drawable.shake_pop_face4);
return;
}
}
dialog出现之后,执行了这个:
sensor.unregisterListener(shakelistener);
这样是为了防止用户在已经出现dialog的情况下继续摇,使得dialog重叠。
然后在点击了dialog中的button之后再重新注册,确保只能摇出一个dialog。
防止用户不点击button,于是使用了
alertDialog.setCancelable(false);
alertDialog.setCanceledOnTouchOutside(false);
至此,离线版的摇一摇功能基本实现。
完成效果图:
代码地址:
https://code.csdn.net/u012591761/shake
实际运用
现在完成的这玩意只能自个儿摇着玩,怎么放到实际运用中呢?
根据接口发送请求
确定好业务逻辑,我要发送的数据和公共服务返回数据格式之后,开始吧!
实体类:
public class ResponseSpecialEasyBean extends BaseResponseBean {
private SpecialDetail detail;
public class SpecialDetail{
private String actionsCount;//每天每人已经参加的活动次数
private String sumCount;//每天每人总次数
private String skakeCount;//中奖次数
}
}
执行类:
public class MySpecialUtil extends JsonParseBaseUtil{
private Context context;
private Handler handler;
private ResponseSpecialBean responseSpecialBean;
private ResponseSpecialEasyBean responseSpecialEasyBean;
public MySpecialUtil(Context context, Handler handler) {
super();
this.context = context;
this.handler = handler;
}
public void getMemberShakeActions() {
// TODO Auto-generated method stub
new Thread() {
public void run() {
handler.sendEmptyMessage(HandlerCASE.MSG_DIALOG_SHOW);
try {
JSONObject object1 = new JSONObject();
JSONObject reqStr = new JSONObject();
object1.put("orderSourceId", Constant.orderSourceId);
object1.put("userId", Constant.userId);
object1.put("orderChannel", Constant.orderChannel);
object1.put("mobilePhoneModel", android.os.Build.MODEL);
reqStr.put("cmd", "getMemberShakeActions");
reqStr.put("params", object1);
String request = formatJson(reqStr.toString());
String response = "";
try {
response = NetManager.getInstance(context)
.dopostAsString(Constant.BASE_TEST_URL,
request);
Log.i("shake", response);
} catch (Exception e) {
// TODO: handle exception
handler.sendEmptyMessage(HandlerCASE.MSG_NET_ERROR);
handler.sendEmptyMessage(HandlerCASE.MSG_DIALOG_CANL);
return;
}
setResponseSpecialEasyBean(getGson().fromJson(response,
ResponseSpecialEasyBean.class));
handler.sendEmptyMessage(HandlerCASE.MSG_DONE);
handler.sendEmptyMessage(HandlerCASE.MSG_DIALOG_CANL);
} catch (Exception e) {
// TODO: handle exception
handler.sendEmptyMessage(HandlerCASE.MSG_FAIL);
handler.sendEmptyMessage(HandlerCASE.MSG_DIALOG_CANL);
}
};
}.start();
}
启了一个线程向接口发送请求,并将返回的数据封装到实体类中。
设置handle
Handler handler=new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HandlerCASE.MSG_DIALOG_SHOW:
showLoadingDialog(false);
break;
case HandlerCASE.MSG_DIALOG_CANL:
cancelLoadingDialog(false);
break;
case HandlerCASE.MSG_NET_ERROR:
tip(Constant.responseExceptionError);
break;
case HandlerCASE.MSG_FAIL:
tip(Constant.responseError);
break;
case HandlerCASE.MSG_DONE:
ResponseSpecialEasyBean responseSpecialEasyBean=mySpecialUtil.getResponseSpecialEasyBean();
actionsCount=Integer.parseInt(responseSpecialEasyBean.getSpecialDetail().getActionsCount());
shakeCount=Integer.parseInt(responseSpecialEasyBean.getSpecialDetail().getSkakeCount());
sumCount=Integer.parseInt(responseSpecialEasyBean.getSpecialDetail().getSumCount());
shakeTimesTextView.setText("今天您还可以摇"+(sumCount-actionsCount)+"次");
// showShakeDialog();
break;
case HandlerCASE.MSG_DONE_SECOND:
ResponseSpecialBean responseSpecialBean=mySpecialUtil.getResponseSpecialBean();
responseSpecialBean.getSpecialDetail();
actionsCount=Integer.parseInt(responseSpecialBean.getSpecialDetail().getCountDetail().getActionsCount());
shakeCount=Integer.parseInt(responseSpecialBean.getSpecialDetail().getCountDetail().getSkakeCount());
sumCount=Integer.parseInt(responseSpecialBean.getSpecialDetail().getCountDetail().getSumCount());
bonus=responseSpecialBean.getSpecialDetail().getBonus();
shakeTimesTextView.setText("今天您还可以摇"+(sumCount-actionsCount<0?0:sumCount-actionsCount)+"次");
showShakeDialog();
break;
}
}
};
重构代码
将原来onAnimationEnd()
中的代码提取出来,叫做showShakeDialog()
重写onAnimationEnd()
:
@Override
public void onAnimationEnd(Animation animation) {
mySpecialUtil.getMemberActions();
}
动画结束的时候发送请求,然后根据返回结果弹出相应的对话框。
至此,功能全部实现了。