http://blog.csdn.net/dawanganban/article/details/20408505
上一篇《是男人就下100層【第一層】——高仿微信界面(7)》中我們實作了下彈式菜單,這一篇我們來看看如何實作微信中的搖一搖功能。
首先我們來布局我們的搖一搖界面
布局檔案如下:
<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#111"
>
<relativelayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerinparent="true" >
<imageview
android:id="@+id/shakebg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerinparent="true"
android:src="@drawable/shakehideimg_man2" />
<linearlayout
android:layout_width="fill_parent"
android:layout_centerinparent="true"
android:orientation="vertical" >
<relativelayout
android:id="@+id/shakeimgup"
android:layout_width="fill_parent"
android:layout_height="190dp"
android:background="#111">
<imageview
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignparentbottom="true"
android:layout_centerhorizontal="true"
android:src="@drawable/shake_logo_up"
/>
</relativelayout>
android:id="@+id/shakeimgdown"
android:src="@drawable/shake_logo_down"
</relativelayout>
</linearlayout>
</relativelayout>
<relativelayout
android:id="@+id/shake_title_bar"
android:layout_height="45dp"
android:background="@drawable/title_bar"
android:gravity="center_vertical" >
<button
android:layout_width="70dp"
android:layout_height="wrap_content"
android:layout_centervertical="true"
android:text="傳回"
android:textsize="14sp"
android:textcolor="#fff"
android:onclick="shake_activity_back"
android:background="@drawable/title_btn_back"/>
<textview
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搖一搖"
android:layout_centerinparent="true"
android:textsize="20sp"
android:textcolor="#ffffff" />
<imagebutton
android:layout_width="67dp"
android:layout_alignparentright="true"
android:layout_marginright="5dp"
android:src="@drawable/mm_title_btn_menu"
android:background="@drawable/title_btn_right"
android:onclick="linshi"
/>
<slidingdrawer
android:id="@+id/slidingdrawer1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="@+id/content"
android:handle="@+id/handle" >
<button
android:id="@+id/handle"
android:layout_height="wrap_content"
android:background="@drawable/shake_report_dragger_up" />
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f9f9f9" >
<imageview
android:layout_width="match_parent"
android:scaletype="fitxy"
android:src="@drawable/shake_line_up" />
</slidingdrawer>
</relativelayout>
這個布局裡面用到了很多相對布局,最外面是一個相對布局(我們先稱為r1),r1内是兩個相對布局(分别稱為r2、r3)和一個抽屜元件,r3是上部标題欄,r2中有一個imageview和一個線性布局,這兩個元件都位于r2的中心,是以上面的線性布局會将下面的imageview遮住,為什麼要遮住,玩過微信搖一搖的朋友應該明白。
slidingdrawer隐藏屏外的内容,并允許使用者通過handle以顯示隐藏内容。它可以垂直或水準滑動,它有倆個view組成,其一是可以拖動的handle,其二是隐藏内容的view.它裡面的控件必須設定布局,在布局檔案中必須指定handle和content.
接下來我們看看如何檢查手機搖晃,搖一搖讓手機震動
package com.example.weixin.listener;
import android.content.context;
import android.hardware.sensor;
import android.hardware.sensorevent;
import android.hardware.sensoreventlistener;
import android.hardware.sensormanager;
import android.util.log;
/**
* 一個檢測手機搖晃的監聽器
*/
public class shakelistener implements sensoreventlistener {
// 速度門檻值,當搖晃速度達到這值後産生作用
private static final int speed_shreshold = 3000;
// 兩次檢測的時間間隔
private static final int uptate_interval_time = 70;
// 傳感器管理器
private sensormanager sensormanager;
// 傳感器
private sensor sensor;
// 重力感應監聽器
private onshakelistener onshakelistener;
// 上下文
private context mcontext;
// 手機上一個位置時重力感應坐标
private float lastx;
private float lasty;
private float lastz;
// 上次檢測時間
private long lastupdatetime;
// 構造器
public shakelistener(context c) {
// 獲得監聽對象
mcontext = c;
start();
}
// 開始
public void start() {
// 獲得傳感器管理器
sensormanager = (sensormanager) mcontext
.getsystemservice(context.sensor_service);
if (sensormanager != null) {
// 獲得重力傳感器
sensor = sensormanager.getdefaultsensor(sensor.type_accelerometer);
}
// 注冊
if (sensor != null) {
sensormanager.registerlistener(this, sensor,
sensormanager.sensor_delay_game);
// 停止檢測
public void stop() {
sensormanager.unregisterlistener(this);
// 設定重力感應監聽器
public void setonshakelistener(onshakelistener listener) {
onshakelistener = listener;
// 重力感應器感應獲得變化資料
public void onsensorchanged(sensorevent event) {
// 現在檢測時間
long currentupdatetime = system.currenttimemillis();
// 兩次檢測的時間間隔
long timeinterval = currentupdatetime - lastupdatetime;
// 判斷是否達到了檢測時間間隔
if (timeinterval < uptate_interval_time)
return;
// 現在的時間變成last時間
lastupdatetime = currentupdatetime;
// 獲得x,y,z坐标
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 獲得x,y,z的變化值
float deltax = x - lastx;
float deltay = y - lasty;
float deltaz = z - lastz;
// 将現在的坐标變成last坐标
lastx = x;
lasty = y;
lastz = z;
double speed = math.sqrt(deltax * deltax + deltay * deltay + deltaz
* deltaz)
/ timeinterval * 10000;
//log.v("thelog", "===========log===================");
// 達到速度閥值,發出提示
if (speed >= speed_shreshold) {
onshakelistener.onshake();
public void onaccuracychanged(sensor sensor, int accuracy) {
// 搖晃監聽接口
public interface onshakelistener {
public void onshake();
}
sensormanager是一個系統提供來管理傳感器的服務。
sensormanager通過getdefaultsensor(int type)方法來擷取指定類型的傳感器。
// 獲得重力傳感器
sensor = sensormanager.getdefaultsensor(sensor.type_accelerometer);
sensormanager提供了一個注冊傳感器的方法:registerlistener
sensormanager.registerlistener(this, sensor,
sensoreventlistener接口定義了兩個方法需要實作
onsensorchanged()方法,當傳感器的值發生改變時觸發該方法。
onaccuracychanged()方法,當傳感器的精度發生改變時觸發該方法。
// 重力感應器感應獲得變化資料
public void onsensorchanged(sensorevent event) {
// 現在檢測時間
long currentupdatetime = system.currenttimemillis();
long timeinterval = currentupdatetime - lastupdatetime;
// 判斷是否達到了檢測時間間隔
if (timeinterval < uptate_interval_time)
return;
// 現在的時間變成last時間
lastupdatetime = currentupdatetime;
// 獲得x,y,z坐标
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 獲得x,y,z的變化值
float deltax = x - lastx;
float deltay = y - lasty;
float deltaz = z - lastz;
// 将現在的坐标變成last坐标
lastx = x;
lasty = y;
lastz = z;
double speed = math.sqrt(deltax * deltax + deltay * deltay + deltaz
* deltaz)
/ timeinterval * 10000;
//log.v("thelog", "===========log===================");
// 達到速度閥值,發出提示
if (speed >= speed_shreshold) {
onshakelistener.onshake();
坐标對應的關系看下圖可知
這裡計算速度的公式是高中學過的知識v=s/t=(a^2+b^2+c^2)/t
double speed = math.sqrt(deltax * deltax + deltay * deltay + deltaz
在activity中建立搖動監聽執行個體并設定監聽
mshakelistener = new shakelistener(this);
mshakelistener.setonshakelistener(new onshakelistener() {
public void onshake() {
//toast.maketext(getapplicationcontext(), "抱歉,暫時沒有找到在同一時刻搖一搖的人。\n再試一次吧!", toast.length_short).show();
startanim(); //開始 搖一搖手掌動畫
mshakelistener.stop();
startvibrato(); //開始 震動
new handler().postdelayed(new runnable(){
@override
public void run(){
//toast.maketext(getapplicationcontext(), "抱歉,暫時沒有找到\n在同一時刻搖一搖的人。\n再試一次吧!", 500).setgravity(gravity.center,0,0).show();
toast mtoast;
mtoast = toast.maketext(getapplicationcontext(),
"抱歉,暫時沒有找到\n在同一時刻搖一搖的人。\n再試一次吧!", 10);
//mtoast.setgravity(gravity.center, 0, 0);
mtoast.show();
mvibrator.cancel();
mshakelistener.start();
}
}, 2000);
});
在設定監聽之前,在activity的oncreate方法中需呀獲得系統提供的振動服務對象
vibrator mvibrator = (vibrator)getapplication().getsystemservice(vibrator_service);
有關vibrator的使用請看我的另一篇博文:http://blog.csdn.net/dawanganban/article/details/17531697
public void startvibrato(){ //定義震動
mvibrator.vibrate( new long[]{500,200,500,200}, -1); //第一個{}裡面是節奏數組, 第二個參數是重複次數,-1為不重複,非-1俄日從pattern的指定下标開始重複
搖一搖的時候還有一個圖檔移動的動畫,設定動畫代碼如下:
public void startanim () { //定義搖一搖動畫動畫
animationset animup = new animationset(true);
translateanimation mytranslateanimup0 = new translateanimation(animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,-0.5f);
mytranslateanimup0.setduration(1000);
translateanimation mytranslateanimup1 = new translateanimation(animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,+0.5f);
mytranslateanimup1.setduration(1000);
mytranslateanimup1.setstartoffset(1000);
animup.addanimation(mytranslateanimup0);
animup.addanimation(mytranslateanimup1);
mimgup.startanimation(animup);
animationset animdn = new animationset(true);
translateanimation mytranslateanimdn0 = new translateanimation(animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,+0.5f);
mytranslateanimdn0.setduration(1000);
translateanimation mytranslateanimdn1 = new translateanimation(animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,0f,animation.relative_to_self,-0.5f);
mytranslateanimdn1.setduration(1000);
mytranslateanimdn1.setstartoffset(1000);
animdn.addanimation(mytranslateanimdn0);
animdn.addanimation(mytranslateanimdn1);
mimgdn.startanimation(animdn);
運作效果如下:
源代碼下載下傳:http://download.csdn.net/detail/lxq_xsyu/6990129