前言

      这几天学习了慕课网上的高仿微信语音聊天功能的课程,自己动手实现了一下。在这里将其实现的过程以及代码分享下来。由于我是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" 

 

 

 

     好了,我们的第一步总算迈出去了。主要就是一个自定义按钮的实现。下一文章中我们将会实现对话框。

       

        

posted on 2015-09-24 17:54  fuly  阅读(7213)  评论(1编辑  收藏  举报