模仿微信語音聊天功能(1)項目介紹及自定義按鈕實現


 

 前言

      這幾天學習了慕課網上的高仿微信語音聊天功能的課程,自己動手實現了一下。在這里將其實現的過程以及代碼分享下來。由於我是android的初學者,里面有不成熟的地方歡迎大家指正。

     項目中所用的圖片可以在這個地方下載:

http://pan.baidu.com/disk/home

 

項目簡單介紹

      首先我們來看最終實現的幾張效果圖吧。如下:

        

                            

 

        我們長安按鈕,就會開始錄音,並且會同時彈出一個麥克風的對話框提示正在錄音。如果在錄音的過程中手指上滑,則會將錄音取消。而如果是錄音時間太短,則會提示錄音時間太短,完成錄音。正常錄音后,會顯示在按鈕上方。

        從圖中,不難看出在整個界面里,上方是是一個 ListView用來顯示錄音,而下面就是一個按鈕。按鈕有三種狀態,即正常錄音,取消錄音和無操作時的默認狀態。與按鈕對應,對話框也有三種狀態,即正常錄音,錄音取消,錄音時間太短這三種狀態。因此完成這個小項目,需要我們具備ListView的基本知識,熟悉自定義按鈕和自定義對話框。同時對android提供的錄音器類和音頻播放的類也要基本了解。

         我打算將這個小項目分成以下幾步來做:

 (1)完成按鈕的交互設計。

(2)完成對話框的設計。

(3)完成錄音時的代碼部分,並集成到之前的代碼里。

(4)完成播放設置,項目也從此結束。

        上面只是我為了學習知識,簡單實現的UI。並不是很好看,讀者有要求,可以自己耐心調一調,讓界面好看一點。在這里我不打算講解所涉及的android中的基礎知識,而是直接寫項目的代碼。好了,我們開始第一步,完成按鈕的設計,即實現按鈕的三種狀態。

 

 

 

按鈕的實現

         首先把主界面給搭建起來,即上方是LisetView,下面是一個我們自定義的按鈕。新建activity_main.xml,代碼如下:

 

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical">
 6     
 7     <ListView 
 8         android:id="@+id/rec_listview"
 9         android:layout_width="match_parent"
10         android:layout_height="0dp"
11         android:layout_weight="1"/>
12     
13     <FrameLayout 
14         android:layout_width="match_parent"
15         android:layout_height="wrap_content"
16         >
17         
18         <com.fuly.util.RecoderButton
19             android:id="@+id/btn_recoder"
20             android:layout_width="120dp"
21             android:layout_height="wrap_content"
22             android:background="@drawable/btn_bg"
23             android:layout_marginTop="5dp"
24             android:layout_marginBottom="3dp"
25             android:text="@string/btn_normal"
26             android:layout_gravity="center"/>
27         <View 
28             android:layout_width="match_parent"
29             android:layout_height="2dp"
30             android:background="@color/black"/>
31         
32     </FrameLayout>
33         
34 
35    
36 
37 </LinearLayout>

 

 

 

          接下來,在res文件下新建文件夾drawable,然后在里面新建btn_bg.xml。這是為自定義的按鈕提供不同狀態下的按鈕背景圖片。代碼如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <selector
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4     <!-- 沒有觸摸時的圖片 -->
 5     <item 
 6          android:state_focused="true"
 7          android:state_enabled="true"
 8          android:state_pressed="false" 
 9          android:drawable="@drawable/btn_normal"/>
10         <!-- 觸摸時的圖片 -->
11      <item 
12         android:state_enabled="true"
13         android:state_pressed="true"
14         android:drawable="@drawable/btn_press"/>
15        <item 
16         android:state_enabled="true"
17         android:state_checked="true"
18         android:drawable="@drawable/btn_press"/>
19      
20      
21      <!-- 默認時的背景圖片-->
22      <item 
23       
24          android:drawable="@drawable/btn_normal"/>
25     
26 </selector>

 

          然后在res下的values文件夾下的strings里面,定義按鈕需要顯示的文本,如下:

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3 
 4     <string name="app_name">irecoder</string>
 5     <string name="action_settings">Settings</string>
 6      <string name="btn_normal">按住 錄音</string>
 7      <string name="btn_recoding">松開 結束</string>
 8      <string name="btn_cancel">手指上滑,取消錄音 錄音</string>
 9     
10 
11 </resources>

 

   接來准備工作都做的差不多了。然后實現我們的自定義按鈕。新建類RecoderButton,該類繼承自Button。具體代碼如下:

 

  1 package com.fuly.util;
  2 
  3 
  4 import com.fuly.irecoder.R;
  5 
  6 import android.content.Context;
  7 import android.util.AttributeSet;
  8 import android.view.MotionEvent;
  9 import android.widget.Button;
 10 
 11 
 12 public class RecoderButton extends Button{
 13     
 14     //按鈕的三個狀態
 15     
 16     private static final int STATE_NORMAL = 1;//正常
 17     private static final int STATE_RECODING = 2;//錄音狀態
 18     private static final int STATE_CACLE = 3;//取消狀態
 19     
 20     private int mCurState = STATE_NORMAL;//記錄當前按鈕狀態
 21     
 22     private int Y = 50;//限定手指移動的上下寬度
 23     
 24     
 25     
 26 
 27     public RecoderButton(Context context, AttributeSet attrs) {
 28         super(context, attrs);
 29     
 30     }
 31     
 32     
 33     
 34     //捕捉按鈕點擊事件
 35     public boolean onTouchEvent(MotionEvent event) {
 36         
 37         int x = (int) event.getX();
 38         int y =(int)event.getY();
 39         
 40         switch(event.getAction()){
 41         
 42         
 43         case MotionEvent.ACTION_DOWN:
 44             
 45             changeState(STATE_RECODING);//按下按鈕,改變按鈕狀態
 46             
 47             break;
 48         case MotionEvent.ACTION_MOVE:
 49             
 50             if(wantCancel(x,y)){ //如果檢測到取消,則改變按鈕狀態為取消
 51                 
 52             changeState(STATE_CACLE);
 53             
 54             }else{
 55                 changeState(STATE_RECODING);
 56             }
 57             
 58             break;
 59         case MotionEvent.ACTION_UP:
 60             
 61             reset();//各種設置復位
 62             
 63             break;
 64             default:
 65                 break;
 66         }
 67         
 68         return super.onTouchEvent(event);
 69     }
 70 
 71 
 72 
 73     //復位
 74     private void reset() {
 75         
 76         mCurState = STATE_NORMAL;
 77         changeState(STATE_NORMAL);
 78         
 79     }
 80 
 81 
 82 
 83     //檢查手指移動范圍,從而確定用戶是否想取消錄音
 84     private boolean wantCancel(int x, int y) {
 85         
 86         if(x<0||x>getWidth()){
 87             
 88             return true;
 89         }
 90         
 91         if(y<0||y>getHeight()+Y){
 92             return true;
 93         }
 94         return false;
 95     }
 96 
 97 
 98     
 99     //改變狀態,包括按鈕等操作
100     private void changeState(int state) {
101         
102         if(mCurState != state){
103             
104             mCurState = state;
105             
106         }
107         
108         switch(mCurState){
109               
110         case STATE_NORMAL:
111             
112             setText(R.string.btn_normal);
113             
114             break;
115         case STATE_RECODING:
116             
117             setText(R.string.btn_recoding);
118             
119             break;
120         case STATE_CACLE:
121             
122             setText(R.string.btn_cancel);
123             
124             break;
125             default:
126                 break;
127         
128         }
129         
130     }
131     
132     
133 
134 }

 

       最后,我們在主類中加載activity_main布局。如下:

 1 package com.fuly.irecoder;
 2 
 3 import android.os.Bundle;
 4 import android.app.Activity;
 5 import android.view.Menu;
 6 
 7 public class MainActivity extends Activity {
 8 
 9   
10     protected void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12         setContentView(R.layout.activity_main);
13     }
14 
15 
16     @Override
17     public boolean onCreateOptionsMenu(Menu menu) {
18         // Inflate the menu; this adds items to the action bar if it is present.
19         getMenuInflater().inflate(R.menu.main, menu);
20         return true;
21     }
22     
23 }

 

 

    然后我們運行這個android項目即可。就會發現隨着我們手指的移動,按鈕呈現出我們想要的狀態。

 

 

當然了,為了好看,我們在AndroidManifest文件里讓app全屏顯示。只需要加上這么一句即可:

1  android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" 

 

 

 

     好了,我們的第一步總算邁出去了。主要就是一個自定義按鈕的實現。下一文章中我們將會實現對話框。

       

        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM