閱讀141 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Android 高仿微信界麵

https://blog.csdn.net/dawanganban/article/details/20408505

上一篇《是男人就下100層【第一層】——高仿微信界麵(7)》中我們實現了下彈式菜單,這一篇我們來看看如何實現微信中的搖一搖功能。

首先我們來布局我們的搖一搖界麵


布局文件如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical"  
  6.     android:background="#111"  
  7.     >  
  8.       
  9.     <RelativeLayout  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="fill_parent"  
  12.         android:layout_centerInParent="true" >  
  13.               
  14.         <ImageView  
  15.             android:id="@+id/shakeBg"  
  16.             android:layout_width="wrap_content"  
  17.             android:layout_height="wrap_content"  
  18.             android:layout_centerInParent="true"          
  19.             android:src="@drawable/shakehideimg_man2" />  
  20.           
  21.         <LinearLayout  
  22.             android:layout_width="fill_parent"  
  23.             android:layout_height="wrap_content"  
  24.             android:layout_centerInParent="true"  
  25.             android:orientation="vertical" >  
  26.               
  27.             <RelativeLayout  
  28.                 android:id="@+id/shakeImgUp"     
  29.                 android:layout_width="fill_parent"  
  30.                 android:layout_height="190dp"                 
  31.                 android:background="#111">                 
  32.                 <ImageView                     
  33.                     android:layout_width="wrap_content"  
  34.                     android:layout_height="wrap_content"  
  35.                     android:layout_alignParentBottom="true"  
  36.                     android:layout_centerHorizontal="true"                                
  37.                     android:src="@drawable/shake_logo_up"  
  38.                      />                  
  39.             </RelativeLayout>  
  40.             <RelativeLayout  
  41.                 android:id="@+id/shakeImgDown"  
  42.                 android:layout_width="fill_parent"  
  43.                 android:layout_height="190dp"                 
  44.                 android:background="#111">                 
  45.                 <ImageView                     
  46.                     android:layout_width="wrap_content"  
  47.                     android:layout_height="wrap_content"  
  48.                     android:layout_centerHorizontal="true"                                
  49.                     android:src="@drawable/shake_logo_down"  
  50.                      />                  
  51.             </RelativeLayout>   
  52.         </LinearLayout>  
  53.     </RelativeLayout>  
  54.       
  55.     <RelativeLayout   
  56.         android:id="@+id/shake_title_bar"   
  57.         android:layout_width="fill_parent"  
  58.         android:layout_height="45dp"  
  59.         android:background="@drawable/title_bar"  
  60.         android:gravity="center_vertical"  >  
  61.             <Button  
  62.                 android:layout_width="70dp"  
  63.                 android:layout_height="wrap_content"  
  64.                 android:layout_centerVertical="true"  
  65.                 android:text="返回"  
  66.                 android:textSize="14sp"  
  67.                 android:textColor="#fff"  
  68.                 android:onClick="shake_activity_back"  
  69.                 android:background="@drawable/title_btn_back"/>    
  70.             <TextView  
  71.                 android:layout_width="wrap_content"   
  72.                 android:layout_height="wrap_content"   
  73.                 android:text="搖一搖"  
  74.                 android:layout_centerInParent="true"  
  75.                 android:textSize="20sp"       
  76.                 android:textColor="#ffffff" />   
  77.             <ImageButton   
  78.                 android:layout_width="67dp"   
  79.                 android:layout_height="wrap_content"  
  80.                 android:layout_alignParentRight="true"   
  81.                 android:layout_centerVertical="true"  
  82.                 android:layout_marginRight="5dp"  
  83.                 android:src="@drawable/mm_title_btn_menu"  
  84.                 android:background="@drawable/title_btn_right"  
  85.                 android:onClick="linshi"   
  86.                 />        
  87.     </RelativeLayout>  
  88.       
  89.   
  90.     <SlidingDrawer  
  91.         android:id="@+id/slidingDrawer1"  
  92.         android:layout_width="match_parent"  
  93.         android:layout_height="match_parent"  
  94.         android:content="@+id/content"  
  95.         android:handle="@+id/handle" >  
  96.         <Button  
  97.             android:id="@+id/handle"  
  98.             android:layout_width="wrap_content"  
  99.             android:layout_height="wrap_content"       
  100.                     
  101.             android:background="@drawable/shake_report_dragger_up" />  
  102.         <LinearLayout  
  103.             android:id="@+id/content"  
  104.             android:layout_width="match_parent"  
  105.             android:layout_height="match_parent"  
  106.             android:background="#f9f9f9" >              
  107.             <ImageView  
  108.                 android:layout_width="match_parent"  
  109.                 android:layout_height="wrap_content"  
  110.                 android:scaleType="fitXY"  
  111.                 android:src="@drawable/shake_line_up" />  
  112.         </LinearLayout>  
  113.     </SlidingDrawer>  
  114.   
  115. </RelativeLayout>  
這個布局裏麵用到了很多相對布局,最外麵是一個相對布局(我們先稱為R1),R1內是兩個相對布局(分別稱為R2、R3)和一個抽屜組件,R3是上部標題欄,R2中有一個ImageView和一個線性布局,這兩個組件都位於R2的中心,所以上麵的線性布局會將下麵的ImageView遮住,為什麼要遮住,玩過微信搖一搖的朋友應該明白。

SlidingDrawer隱藏屏外的內容,並允許用戶通過handle以顯示隱藏內容。它可以垂直或水平滑動,它有倆個View組成,其一是可以拖動的handle,其二是隱藏內容的View.它裏麵的控件必須設置布局,在布局文件中必須指定handle和content.

接下來我們看看如何檢查手機搖晃,搖一搖讓手機震動

  1. package com.example.weixin.listener;  
  2.   
  3. import android.content.Context;  
  4. import android.hardware.Sensor;  
  5. import android.hardware.SensorEvent;  
  6. import android.hardware.SensorEventListener;  
  7. import android.hardware.SensorManager;  
  8. import android.util.Log;  
  9.   
  10. /** 
  11.  * 一個檢測手機搖晃的監聽器 
  12.  */  
  13. public class ShakeListener implements SensorEventListener {  
  14.     // 速度閾值,當搖晃速度達到這值後產生作用  
  15.     private static final int SPEED_SHRESHOLD = 3000;  
  16.     // 兩次檢測的時間間隔  
  17.     private static final int UPTATE_INTERVAL_TIME = 70;  
  18.     // 傳感器管理器  
  19.     private SensorManager sensorManager;  
  20.     // 傳感器  
  21.     private Sensor sensor;  
  22.     // 重力感應監聽器  
  23.     private OnShakeListener onShakeListener;  
  24.     // 上下文  
  25.     private Context mContext;  
  26.     // 手機上一個位置時重力感應坐標  
  27.     private float lastX;  
  28.     private float lastY;  
  29.     private float lastZ;  
  30.     // 上次檢測時間  
  31.     private long lastUpdateTime;  
  32.   
  33.     // 構造器  
  34.     public ShakeListener(Context c) {  
  35.         // 獲得監聽對象  
  36.         mContext = c;  
  37.         start();  
  38.     }  
  39.   
  40.     // 開始  
  41.     public void start() {  
  42.         // 獲得傳感器管理器  
  43.         sensorManager = (SensorManager) mContext  
  44.                 .getSystemService(Context.SENSOR_SERVICE);  
  45.         if (sensorManager != null) {  
  46.             // 獲得重力傳感器  
  47.             sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);  
  48.         }  
  49.         // 注冊  
  50.         if (sensor != null) {  
  51.             sensorManager.registerListener(this, sensor,  
  52.                     SensorManager.SENSOR_DELAY_GAME);  
  53.         }  
  54.   
  55.     }  
  56.   
  57.     // 停止檢測  
  58.     public void stop() {  
  59.         sensorManager.unregisterListener(this);  
  60.     }  
  61.   
  62.     // 設置重力感應監聽器  
  63.     public void setOnShakeListener(OnShakeListener listener) {  
  64.         onShakeListener = listener;  
  65.     }  
  66.   
  67.     // 重力感應器感應獲得變化數據  
  68.     public void onSensorChanged(SensorEvent event) {  
  69.         // 現在檢測時間  
  70.         long currentUpdateTime = System.currentTimeMillis();  
  71.         // 兩次檢測的時間間隔  
  72.         long timeInterval = currentUpdateTime - lastUpdateTime;  
  73.         // 判斷是否達到了檢測時間間隔  
  74.         if (timeInterval < UPTATE_INTERVAL_TIME)  
  75.             return;  
  76.         // 現在的時間變成last時間  
  77.         lastUpdateTime = currentUpdateTime;  
  78.   
  79.         // 獲得x,y,z坐標  
  80.         float x = event.values[0];  
  81.         float y = event.values[1];  
  82.         float z = event.values[2];  
  83.   
  84.         // 獲得x,y,z的變化值  
  85.         float deltaX = x - lastX;  
  86.         float deltaY = y - lastY;  
  87.         float deltaZ = z - lastZ;  
  88.   
  89.         // 將現在的坐標變成last坐標  
  90.         lastX = x;  
  91.         lastY = y;  
  92.         lastZ = z;  
  93.   
  94.         double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ  
  95.                 * deltaZ)  
  96.                 / timeInterval * 10000;  
  97.         //Log.v("thelog", "===========log===================");  
  98.         // 達到速度閥值,發出提示  
  99.         if (speed >= SPEED_SHRESHOLD) {  
  100.             onShakeListener.onShake();  
  101.         }  
  102.     }  
  103.   
  104.     public void onAccuracyChanged(Sensor sensor, int accuracy) {  
  105.   
  106.     }  
  107.   
  108.     // 搖晃監聽接口  
  109.     public interface OnShakeListener {  
  110.         public void onShake();  
  111.     }  
  112.   
  113. }  
SensorManager是一個係統提供來管理傳感器的服務。

SensorManager通過getDefaultSensor(int type)方法來獲取指定類型的傳感器。

  1. // 獲得重力傳感器  
  2. sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);  
SensorManager提供了一個注冊傳感器的方法:registerListener

  1. sensorManager.registerListener(this, sensor,  
  2.                     SensorManager.SENSOR_DELAY_GAME);  
SensorEventListener接口定義了兩個方法需要實現

onSensorChanged()方法,當傳感器的值發生改變時觸發該方法。

onAccuracyChanged()方法,當傳感器的精度發生改變時觸發該方法。

  1. // 重力感應器感應獲得變化數據  
  2. public void onSensorChanged(SensorEvent event) {  
  3.     // 現在檢測時間  
  4.     long currentUpdateTime = System.currentTimeMillis();  
  5.     // 兩次檢測的時間間隔  
  6.     long timeInterval = currentUpdateTime - lastUpdateTime;  
  7.     // 判斷是否達到了檢測時間間隔  
  8.     if (timeInterval < UPTATE_INTERVAL_TIME)  
  9.         return;  
  10.     // 現在的時間變成last時間  
  11.     lastUpdateTime = currentUpdateTime;  
  12.   
  13.     // 獲得x,y,z坐標  
  14.     float x = event.values[0];  
  15.     float y = event.values[1];  
  16.     float z = event.values[2];  
  17.   
  18.     // 獲得x,y,z的變化值  
  19.     float deltaX = x - lastX;  
  20.     float deltaY = y - lastY;  
  21.     float deltaZ = z - lastZ;  
  22.   
  23.     // 將現在的坐標變成last坐標  
  24.     lastX = x;  
  25.     lastY = y;  
  26.     lastZ = z;  
  27.   
  28.     double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ  
  29.             * deltaZ)  
  30.             / timeInterval * 10000;  
  31.     //Log.v("thelog", "===========log===================");  
  32.     // 達到速度閥值,發出提示  
  33.     if (speed >= SPEED_SHRESHOLD) {  
  34.         onShakeListener.onShake();  
  35.     }  
  36. }  
坐標對應的關係看下圖可知

這裏計算速度的公式是高中學過的知識v=s/t=(a^2+b^2+c^2)/t

  1. double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ  
  2.                 * deltaZ)  
  3.                 / timeInterval * 10000;  

在Activity中創建搖動監聽實例並設置監聽

  1. mShakeListener = new ShakeListener(this);  
  2.        mShakeListener.setOnShakeListener(new OnShakeListener() {  
  3.         public void onShake() {  
  4.             //Toast.makeText(getApplicationContext(), "抱歉,暫時沒有找到在同一時刻搖一搖的人。\n再試一次吧!", Toast.LENGTH_SHORT).show();  
  5.             startAnim();  //開始 搖一搖手掌動畫  
  6.             mShakeListener.stop();  
  7.             startVibrato(); //開始 震動  
  8.             new Handler().postDelayed(new Runnable(){  
  9.                 @Override  
  10.                 public void run(){  
  11.                     //Toast.makeText(getApplicationContext(), "抱歉,暫時沒有找到\n在同一時刻搖一搖的人。\n再試一次吧!", 500).setGravity(Gravity.CENTER,0,0).show();  
  12.                     Toast mtoast;  
  13.                     mtoast = Toast.makeText(getApplicationContext(),  
  14.                              "抱歉,暫時沒有找到\n在同一時刻搖一搖的人。\n再試一次吧!"10);  
  15.                            //mtoast.setGravity(Gravity.CENTER, 0, 0);  
  16.                            mtoast.show();  
  17.                            mVibrator.cancel();  
  18.                            mShakeListener.start();  
  19.                 }  
  20.             }, 2000);  
  21.         }  
  22.     });  

在設置監聽之前,在Activity的onCreate方法中需呀獲得係統提供的振動服務對象

  1. Vibrator mVibrator = (Vibrator)getApplication().getSystemService(VIBRATOR_SERVICE);  
有關Vibrator的使用請看我的另一篇博文:https://blog.csdn.net/dawanganban/article/details/17531697

  1. public void startVibrato(){     //定義震動  
  2.         mVibrator.vibrate( new long[]{500,200,500,200}, -1); //第一個{}裏麵是節奏數組, 第二個參數是重複次數,-1為不重複,非-1俄日從pattern的指定下標開始重複  
  3.     }  
搖一搖的時候還有一個圖片移動的動畫,設置動畫代碼如下:

  1. public void startAnim () {   //定義搖一搖動畫動畫  
  2.     AnimationSet animup = new AnimationSet(true);  
  3.     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);  
  4.     mytranslateanimup0.setDuration(1000);  
  5.     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);  
  6.     mytranslateanimup1.setDuration(1000);  
  7.     mytranslateanimup1.setStartOffset(1000);  
  8.     animup.addAnimation(mytranslateanimup0);  
  9.     animup.addAnimation(mytranslateanimup1);  
  10.     mImgUp.startAnimation(animup);  
  11.       
  12.     AnimationSet animdn = new AnimationSet(true);  
  13.     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);  
  14.     mytranslateanimdn0.setDuration(1000);  
  15.     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);  
  16.     mytranslateanimdn1.setDuration(1000);  
  17.     mytranslateanimdn1.setStartOffset(1000);  
  18.     animdn.addAnimation(mytranslateanimdn0);  
  19.     animdn.addAnimation(mytranslateanimdn1);  
  20.     mImgDn.startAnimation(animdn);    
  21. }  
運行效果如下:



源代碼下載:https://download.csdn.net/detail/lxq_xsyu/6990129

最後更新:2017-04-03 12:55:22

  上一篇:go Oracle Greatest()函數
  下一篇:go Eclipse打包工具 Fatjar clipse插件安裝方法 如何使用fat打包運行