Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 0
打印 上一主题 下一主题

在Android4.0中Contacts拨号盘点击事件详析(源码)

[复制链接]

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
跳转到指定楼层
楼主
发表于 2016-7-16 16:37:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
网址:
http://blog.sina.com.cn/s/blog_9f233c070101bqvp.html
--------------------------------------------------------------------------
前文有朋友回复说想深入了解一下拨号盘源码的实现,也许是上文中,我对此说的不够细致,现将拨号盘点击事件及处理,拨号键的点击等。
对于拨号盘的界面显示,在此就不在浪费大家的时间,不清楚的朋友可以点击下面的连接(拨号盘界面的显示)。下面主要描述一下点击拨号盘中某个按钮后,是怎么将对应的数字显示在输入框中和点击控制键(拨号,删除,搜索)所触发的事件。
1.拨号盘中数字键
在DialpadFragment.java中,通过onCreateView方法,加载出了拨号界面,在该方法中有一句这样的令人费解的代码
  View oneButton = fragmentView.findViewById(R.id.one);
if (oneButton != null) {
  setupKeypad(fragmentView);
}
首先通过View类的findViewById方法获得oneButton对象,当oneButton不为null的时候才绑定键盘。然后调用setupKeypad(fragmentView)方法,进行键盘监听事件的绑定,现截取代码片段与大家分享。
private void setupKeypad(View fragmentView) {
        // Setup the listeners for the buttons
View view = fragmentView.findViewById(R.id.one);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
….
}
废话不多说,看代码!
View view = fragmentView.findViewById(R.id.one);
   通过View类的findViewById方法获得oneButton按钮,下面将分设置点击事件和长按事件两部分来进行描述。
1.1数字键盘的点击事件
view.setOnClickListener(this);
为其设置点击事件监听器。此时该监听器为当前对象this,看样子该Fragment实现了view的onClickListener接口,是不是呢?我们看代码
DialpadFragment extends Fragment implements View.OnClickListener
好,既然如此,肯定要覆盖onClick(View view) 方法,我们继续跟进
onClick方法的片段如下
@Override
public void onClick(View view) {
     switch (view.getId()) {
    case R.id.one: {
           playTone(ToneGenerator.TONE_DTMF_1);
           keyPressed(KeyEvent.KEYCODE_1);
            return;
     }//case结束       。。。
}//switch结束
}//onClick结束
当点击按钮1 时出会触发onClick事件,然后进入R.id.one分支
好,如果该分支后,会看到两个方法的调用,继续跟进playTone(ToneGenerator.TONE_DTMF_1);
这个方法主要是根据不同的按键发出不同的声音,最总调到本地方法,和显示关系不大,就不做详细描述,有需要的朋友自己看一下,java代码比较简单。
keyPressed(KeyEvent.KEYCODE_1);
我们来看这句的代码
private void keyPressed(int keyCode) {
  mHaptic.vibrate();
  KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
  mDigits.onKeyDown(keyCode, event);
  final int length = mDigits.length();
if (length == mDigits.getSelectionStart() && length == mDigits.getSelectionEnd()) {
            mDigits.setCursorVisible(false);
   }
}
第一句mHaptic.vibrate();
我们先来看看mHaptic 到底是个什么东西吧
// Vibration (haptic feedback) for dialer key presses.
private HapticFeedback mHaptic = new HapticFeedback();
该HapticFeedback是一个Android定义的类,该类的vibrate()方法的大体上就是是手机震动一下。
继续跟进
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
mDigits.onKeyDown(keyCode, event);
通过传递过来的键盘码,构造键盘点击事件,然后将该事件交给EditText的子类对象mDigits进行处理。处理后就会将keyCode所代表的字符显示在输入框内。
final int length = mDigits.length();
if (length == mDigits.getSelectionStart() && length == mDigits.getSelectionEnd()) {
   mDigits.setCursorVisible(false);
}
后面几句,就是设置光标的可见与否。onCilck事件我们已经分析完毕,所有按键的点击均会触发该事件,回过头来,我们继续跟进setupKeypad方法。
1.2数字键盘的长按事件
view.setOnLongClickListener(this);
  为view对象设置长按事件,长按事件的监听器还是this,当前的对象,不用多说,该类肯定也是实现了View的OnLongClickListener接口。我们直接看onLongClick方法。
相关代码片段如下:
public boolean onLongClick(View view) {
    final Editable digits = mDigits.getText();
    int id = view.getId();
    switch (id) {
           。。。
     case R.id.one: {
         if (isDigitsEmpty()) {
            if (isVoicemailAvailable()) {
               callVoicemail();
             } else if (getActivity() != null) {
            DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
                    R.string.dialog_voicemail_not_ready_title,
                    R.string.dialog_voicemail_not_ready_message);
dialogFragment.show(getFragmentManager(), "voicemail_not_ready");
             }
             return true;
          }
           return false;
        }//one 处理结束
            。。。
}//switch 语句结束
return false;
}//onLongClick方法结束
公共代码分析
final Editable digits = mDigits.getText();
    int id = view.getId();
获得输入框EditText的输入数据,获得view的id号码,用于switch语句的分支确认。
通过上面的基本操作,我们找到了长按1事件的主体,R.id.one分支
映入眼帘的第一句
  if (isDigitsEmpty())
看代码
private boolean isDigitsEmpty() {
        return mDigits.length() == 0;
}
简单的说就是判断该输入框内是否有输入
当没有输入时首先执行isVoicemailAvailable()方法,我们看源码
private boolean isVoicemailAvailable() {
        try {
            return (TelephonyManager.getDefault().getVoiceMailNumber() != null);
        } catch (SecurityException se) {
            // Possibly no READ_PHONE_STATE privilege.
            Log.w(TAG, "SecurityException is thrown. Maybe privilege isn't sufficient.");
        }
        return false;
    }
通过源码可以看出,该方法实际上是判断了VoiceMailNumber是否为null,按照源码中的意思,这个条件永远成立,有兴趣的朋友可以去看一下源码。
当没有输入且可以拨打voicemail时执行如下
             callVoicemail();
我们查看源码
public void callVoicemail() {
        startActivity(newVoicemailIntent());
        mDigits.getText().clear(); // TODO: Fix bug 1745781
        getActivity().finish();
}
继续跟进
private Intent newVoicemailIntent() {
        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                      Uri.fromParts("voicemail", EMPTY_NUMBER, null));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return intent;
}
不用多说,是跳转到另一个动作,其实voicemail类似于快捷拨号,在settings中可以设置成自己需要拨打的特殊号码,这样当长按1时,就可以自动拨打出去。
在不符合上面条件的前提下
当没有输入而Activity不等于null时执行dialogFragment 的弹出操作,在此不做过多的说明。
通过对1按键的描述,我想大家已经可以按该过程有所了解。
2.拨号盘中删除键
我们从onCreateView方法中,找到
mDelete = mAdditionalButtonsRow.findViewById(R.id.deleteButton);
mDelete.setOnClickListener(this);
mDelete.setOnLongClickListener(this);
接下来我们分删除键的点击事件和长按事件两部分描述。
2.1 删除键的点击描述
通过上文mDelete.setOnClickListener(this),我们知道,单击事件需要找onClick方法,直接定位到指定位置。
  public void onClick(View view) {
        switch (view.getId()) {
             。。。。。。。。
        case R.id.deleteButton: {
                keyPressed(KeyEvent.KEYCODE_DEL);
                return;
         }
。。。。。。
        }
   同上,最终调用
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
   mDigits.onKeyDown(keyCode, KeyEvent.KEYCODE_DEL);
   mDigits就会将光标的前一个位置的字符删除。
2.2 删除键长按描述
废话不说,直接看定位代码
   public boolean onLongClick(View view) {
               ………………..
                switch (id) {
            case R.id.deleteButton: {
                digits.clear();
                mDelete.setPressed(false);
                return true;
            }
………..
}
}
Digits.clear()方法,直接清空输入框内的数字
mDelete.setPressed(false); 设置删除键的按下状态
3.拨号盘中拨号键
同理,在onClick方法中找到拨号键
           …………..
  case R.id.dialButton: {
              mHaptic.vibrate();
              dialButtonPressed();
              return;
            }
  ……………….
mHaptic.vibrate(); 震动一下
继续查看dialButtonPressed()方法
在该方法中,通过输入域内是否为null建立了两个分支结构,在两个分支中均做了比较多的分支,最终页面实现跳转或对话框的弹出等,比较简单,需要的朋友请自己查看dialButtonPressed()方法的源码。
4.拨号盘中搜索键
搜索按键的处理与其它按键的处理类似,但是又有些不同,在后文将详细的分析一下,感兴趣的朋友自己走一下onClick流程。
希望我的分析,对朋友你有所帮助。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Comsenz Inc.

GMT+8, 2025-12-15 01:50 , Processed in 0.014609 second(s), 8 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表