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

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

NavigationBar的创建

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

try {
boolean showNav = mWindowManagerService.hasNavigationBar();
/// M: Support Smartbook Feature.
if (true) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
mNavigationBarView =
(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); mNavigationBarView.setDisabledFlags(mDisabled);
mNavigationBarView.setBar(this);
mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
checkUserAutohide(v, event);
return false;
}});
}
} catch (RemoteException ex) {
// no window manager? good luck with that
}

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按钮事件的绑定

private void prepareNavigationBarView() {
mNavigationBarView.reorient(); mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}

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

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

public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
int x, y; switch (action) {
case MotionEvent.ACTION_DOWN:
//Slog.d("KeyButtonView", "press");
mDownTime = SystemClock.uptimeMillis();
setPressed(true);
if (mCode != ) {
sendEvent(KeyEvent.ACTION_DOWN, , mDownTime);
} else {
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
}
break;
case MotionEvent.ACTION_MOVE:
x = (int)ev.getX();
y = (int)ev.getY();
setPressed(x >= -mTouchSlop
&& x < getWidth() + mTouchSlop
&& y >= -mTouchSlop
&& y < getHeight() + mTouchSlop);
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
if (mCode != ) {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
}
break;
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed();
setPressed(false);
if (mCode != ) {
if (doIt) {
sendEvent(KeyEvent.ACTION_UP, );
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
playSoundEffect(SoundEffectConstants.CLICK);
} else {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
} else {
// no key code, just a regular ImageView
if (doIt) {
performClick();
}
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
}
break;
} return true;
}

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

<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_back"
systemui:keyCode=""
android:layout_weight=""
android:scaleType="center"
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/accessibility_back"
/>

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

Android 如何Android中自定义Navigationbar的更多相关文章

  1. android代码优化----ListView中自定义adapter的封装(ListView的模板写法)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  2. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

  3. Android中自定义Activity和Dialog的位置大小背景和透明度等demo

    1.自定义Activity显示样式 先在res/values下建colors.xml文件,写入: <?xml version="1.0" encoding="utf ...

  4. Android开发如何在4.0及以上系统中自定义TitleBar

    本文将通过一个实例讲解怎么实现在4.0及以上系统版本中实现自定义TitleBar,这只是我自己找到的一种方法; xml布局文件 activity_main.xml <RelativeLayout ...

  5. Android中自定义Activity和Dialog的位置大小背景和透明度等

    1.自定义Activity显示样式 先在res/values下建colors.xml文件,写入: view plainprint? 1. <?xml version="1.0" ...

  6. Android中自定义veiw使用Java中的回调方法

    //------------------MainActivity----中---------------------------------- import android.os.Bundle;imp ...

  7. android开发:Android 中自定义View的应用

    大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习惯了Android 传统的页面布局方式,如下代码: <?xml version="1.0&q ...

  8. android中自定义view构造函数ContentItemView(Context context, AttributeSet paramAttributeSet)的用处

    自己定义一个view <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...

  9. Android中自定义组合控件

    Android中自定义控件的情况非常多,一般自定义控件可以分为两种:继承控件及组合控件.前者是通过继承View或其子类,重写方法实现自定义的显示及事件处理方式:后者是通过组合已有的控件,来实现结构的简 ...

随机推荐

  1. golang beego cache

    package main import ( "fmt" "github.com/astaxie/beego/cache" "time" ) ...

  2. JS 实现图片模态框,幻灯片,跑马灯功能

    网站中常用的幻灯片和模态框,使用 HTML.JavaScript 与 CSS 来创建 Lightbox,类似相册预览功能.可以运用到视频网站,商城,相册上去 参考了菜鸟教程,有兴趣自己去看 HTML/ ...

  3. jQuery选择器,Ajax请求

    jQuery选择器: $("#myELement") 选择id值等于myElement的元素,id值不能重复在文档中只能有一个id值是myElement所以得到的是唯一的元素 $( ...

  4. Python Jsonpath模块用法

    在使用Python做自动化校验的时候,经常会从Json数据中取值,所以会用到Jsonpath模块,这里做个简单的总结 1.关于jsonpath用来解析多层嵌套的json数据;JsonPath 是一种信 ...

  5. 10. ZooKeeper之搭建伪集群模式。

    转自:https://blog.csdn.net/en_joker/article/details/78673456 在集群和单机两种模式下,我们基本完成了分别针对生产环境和开发环境ZooKeeper ...

  6. HTML基础第十讲---排版卷标

    转自:https://i.cnblogs.com/posts?categoryid=1121494 网页的排版部份也是很重要的一环,有些现成的卷标就可以让您轻易的完成缩排或是一些特殊格式的编排喔! [ ...

  7. COOKIE传值

    1.遍历所有cookie foreach (string  _key in Request.Cookies.AllKeys)//遍历主键            {                Htt ...

  8. ios系统和某些移动端background-attachment:fixed不兼容性

    固定背景不动:background-attachment:fixed; ios系统和某些移动端background-attachment:fixed不兼容性,没有任何效果,但可以hack一下就可以了, ...

  9. Docker 部署Dotnet Core MVC项目

    原文:Docker 部署Dotnet Core MVC项目 1.dotnet core创建项目 dotnet new mvc -o myweb cd myweb 然后就是业务代码的编辑,增删改查乱七八 ...

  10. 【例 7-12 UVA - 1343】The Rotation Game

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 迭代加深搜索. 每次抽动操作最多只会让中间那一块的区域离目标的"距离"减少1. 以这个作为剪枝. 枚举最大深度. ...