如何Android中自定义Navigationbar

  • 原文地址:http://www.it165.net/pro/html/201503/35530.html

  • 在如何控制android系统中NavigationBar 的显示与隐藏文章里简要地介绍了Navigationbar的背景知识,

    NavigationBar的代码是放在... rameworksasepackagesSystemUI路径下面的。该路径下的工程主要负责手机中系统级UI的显示部分,如下图框中选中部分(包含其中的通知栏的显示),USB的连接,截屏等等。

    如何Android中自定义Navigationbar_第1张图片

    NavigationBar的创建

    navigationbar 的代码是在SystemUI工程SystemUI/src/com/android/systemui/statusbar/phone的路径下,其中navigationbar是由PhoneStatusBar.java类创建的。在该类的makeStatusBarView()方法下,可以看到创建Navigationbar的过程:

     

    view source print ?
    01. try {
    02. boolean showNav = mWindowManagerService.hasNavigationBar();
    03. /// M: Support Smartbook Feature.
    04. if (true) Log.v(TAG, "hasNavigationBar=" + showNav);
    05. if (showNav) {
    06. mNavigationBarView =
    07. (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
    08.  
    09. mNavigationBarView.setDisabledFlags(mDisabled);
    10. mNavigationBarView.setBar(this);
    11. mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
    12. @Override
    13. public boolean onTouch(View v, MotionEvent event) {
    14. checkUserAutohide(v, event);
    15. return false;
    16. }});
    17. }
    18. catch (RemoteException ex) {
    19. // no window manager? good luck with that
    20. }
    WindowManagerService通过判断是否需要显示NavigationBar来决定是否需要创建NavigationBarView, NavigationBarView即为我们看到视图的view了,navigation_bar即为NavigationBarView实例化的layout,你可以在SystemUI工程下的layout文件夹下找到。

     

    通过修改navigation_bar布局的方式来自定义NavigationBar的UI。在该layout文件中有这样一个类。com.android.systemui.statusbar.policy.KeyButtonView,它是系统定义的在NavigationBar上的按钮类(后面会讲到),点击会产生波纹的效果。

    NavigationBarView主负责UI的初始化工作,实例化布局,根据屏幕方向先取正确的图片。

    NavigationBar按钮的事件绑定

    NavigationBar按钮上的事件绑定并不是在NavigationBarView里实现,而是在SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java类中完成的。

    通过NavigationBarView对外提供的获取按钮接口来完成按钮的绑定:

    Recent, Home, SearchLight按钮事件的绑定

     

    view source print ?
    01. private void prepareNavigationBarView() {
    02. mNavigationBarView.reorient();
    03.  
    04. mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
    05. mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
    06. mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
    07. mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
    08. updateSearchPanel();
    09. }

     

    Menu, Home, Back按钮事件的绑定:

     

    上面三个按钮都是KeyButtonView类,它们的事件响应过程都是在类本身里面完成的。它们通过onTouchEvent()方法来响应点击事件,

     

    view source print ?
    01. public boolean onTouchEvent(MotionEvent ev) {
    02. final int action = ev.getAction();
    03. int x, y;
    04.  
    05. switch (action) {
    06. case MotionEvent.ACTION_DOWN:
    07. //Slog.d("KeyButtonView", "press");
    08. mDownTime = SystemClock.uptimeMillis();
    09. setPressed(true);
    10. if (mCode != 0) {
    11. sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
    12. else {
    13. // Provide the same haptic feedback that the system offers for virtual keys.
    14. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
    15. }
    16. if (mSupportsLongpress) {
    17. removeCallbacks(mCheckLongPress);
    18. postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
    19. }
    20. break;
    21. case MotionEvent.ACTION_MOVE:
    22. x = (int)ev.getX();
    23. y = (int)ev.getY();
    24. setPressed(x >= -mTouchSlop
    25. && x < getWidth() + mTouchSlop
    26. && y >= -mTouchSlop
    27. && y < getHeight() + mTouchSlop);
    28. break;
    29. case MotionEvent.ACTION_CANCEL:
    30. setPressed(false);
    31. if (mCode != 0) {
    32. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
    33. }
    34. if (mSupportsLongpress) {
    35. removeCallbacks(mCheckLongPress);
    36. }
    37. break;
    38. case MotionEvent.ACTION_UP:
    39. final boolean doIt = isPressed();
    40. setPressed(false);
    41. if (mCode != 0) {
    42. if (doIt) {
    43. sendEvent(KeyEvent.ACTION_UP, 0);
    44. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    45. playSoundEffect(SoundEffectConstants.CLICK);
    46. else {
    47. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
    48. }
    49. else {
    50. // no key code, just a regular ImageView
    51. if (doIt) {
    52. performClick();
    53. }
    54. }
    55. if (mSupportsLongpress) {
    56. removeCallbacks(mCheckLongPress);
    57. }
    58. break;
    59. }
    60.  
    61. return true;
    62. }

    mCode是用来判断该触摸是来自于哪个button,表示不同button的keycode在KeyEvent中类都有定义。该值在布局文件中通过获取navigationbar_view中的systemui:keycode属性来获得,下面是layout布局文件中back相应代码段:

     

     

    view source print ?
    01. "@+id/back"
    02. android:layout_width="@dimen/navigation_key_width"
    03. android:layout_height="match_parent"
    04. android:src="@drawable/ic_sysbar_back"
    05. systemui:keyCode="4"
    06. android:layout_weight="0"
    07. android:scaleType="center"
    08. systemui:glowBackground="@drawable/ic_sysbar_highlight"
    09. android:contentDescription="@string/accessibility_back"
    10. />

    在onTouch中方法通过sendEvent()方法来执行不同的keycode响应事件,该方法会创建一个包含keycode的KeyEvent对象封装,然后通过injectInputEvent()向InputManager插入一个事件,再发送出去。

你可能感兴趣的:(Android开发)