如何Android中自定义Navigationbar

如何Android中自定义Navigationbar,第1张

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

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

NavigationBar的创建

navigationbar

的代码是在SystemUI工程SystemUI/src/com/android/systemui/statusbar/phone的路径下,其中

navigationbar是由PhoneStatusBarjava类创建的。在该类的makeStatusBarView()方法下,可以看到创建

Navigationbar的过程:

try {

boolean showNav = mWindowManagerServicehasNavigationBar();

/// M: Support Smartbook Feature

if (true) Logv(TAG, "hasNavigationBar=" + showNav);

if (showNav) {

mNavigationBarView =

(NavigationBarView) Viewinflate(context, Rlayoutnavigation_bar, null);

mNavigationBarViewsetDisabledFlags(mDisabled);

mNavigationBarViewsetBar(this);

mNavigationBarViewsetOnTouchListener(new ViewOnTouchListener() {

@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文件中有这样一个类。

comandroidsystemuistatusbarpolicyKeyButtonView,它是系统定义的在

NavigationBar上的按钮类(后面会讲到),点击会产生波纹的效果。

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

NavigationBar按钮的事件绑定

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

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

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

private void prepareNavigationBarView() {

mNavigationBarViewreorient();

mNavigationBarViewgetRecentsButton()setOnClickListener(mRecentsClickListener);

mNavigationBarViewgetRecentsButton()setOnTouchListener(mRecentsPreloadOnTouchListener);

mNavigationBarViewgetHomeButton()setOnTouchListener(mHomeSearchActionListener);

mNavigationBarViewgetSearchLight()setOnTouchListener(mHomeSearchActionListener);

updateSearchPanel();

}

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

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

public boolean onTouchEvent(MotionEvent ev) {

final int action = evgetAction();

int x, y;

switch (action) {

case MotionEventACTION_DOWN:

//Slogd("KeyButtonView", "press");

mDownTime = SystemClockuptimeMillis();

setPressed(true);

if (mCode != 0) {

sendEvent(KeyEventACTION_DOWN, 0, mDownTime);

} else {

// Provide the same haptic feedback that the system offers for virtual keys

performHapticFeedback(HapticFeedbackConstantsVIRTUAL_KEY);

}

if (mSupportsLongpress) {

removeCallbacks(mCheckLongPress);

postDelayed(mCheckLongPress, ViewConfigurationgetLongPressTimeout());

}

break;

case MotionEventACTION_MOVE:

x = (int)evgetX();

y = (int)evgetY();

setPressed(x >= -mTouchSlop

&& x < getWidth() + mTouchSlop

&& y >= -mTouchSlop

&& y < getHeight() + mTouchSlop);

break;

case MotionEventACTION_CANCEL:

setPressed(false);

if (mCode != 0) {

sendEvent(KeyEventACTION_UP, KeyEventFLAG_CANCELED);

}

if (mSupportsLongpress) {

removeCallbacks(mCheckLongPress);

}

break;

case MotionEventACTION_UP:

final boolean doIt = isPressed();

setPressed(false);

if (mCode != 0) {

if (doIt) {

sendEvent(KeyEventACTION_UP, 0);

sendAccessibilityEvent(AccessibilityEventTYPE_VIEW_CLICKED);

playSoundEffect(SoundEffectConstantsCLICK);

} else {

sendEvent(KeyEventACTION_UP, KeyEventFLAG_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相应代码段:

<comandroidsystemuistatusbarpolicyKeyButtonView android:id="@+id/back"

android:layout_width="@dimen/navigation_key_width"

android:layout_height="match_parent"

android:src="@drawable/ic_sysbar_back"

systemui:keyCode="4"

android:layout_weight="0"

android:scaleType="center"

systemui:glowBackground="@drawable/ic_sysbar_highlight"

android:contentDescription="@string/accessibility_back"

/>

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

Android横屏竖屏设置

getWindow()setFlags(WindowManagerLayoutParamsFLAG_FULLSCREEN, WindowManagerLayoutParamsFLAG_FULLSCREEN);//设置成全屏模式

setRequestedOrientation(ActivityInfoSCREEN_ORIENTATION_LANDSCAPE););//强制为横屏

setRequestedOrientation(ActivityInfoSCREEN_ORIENTATION_PORTRAIT);//竖屏

我做的东西里面还用到了去掉标题栏。

我也贴出来

requestWindowFeature(WindowFEATURE_NO_TITLE);

垂直居中:

android:layout_centerVertical="true"

水平居中:

android:layout_centerHorizontal="true"

1hideStatusbarAndTitlebar()隐藏statusbar和titlebar

private void hideStatusbarAndTitlebar() {

final Window win = getWindow();

// No Statusbar

winsetFlags(WindowManagerLayoutParamsFLAG_FULLSCREEN,

WindowManagerLayoutParamsFLAG_FULLSCREEN);

// No Titlebar

requestWindowFeature(WindowFEATURE_NO_TITLE);

}

2设置屏幕显示模式ScreenOrientation

在activity里设置android:screenOrientation的值。

android:screenOrientation的属性有以下值:

unspecified(默 认值,由系统判断状态自动切换),The default value The system chooses the orientation The policy it uses, and therefore the choices made in specific contexts, may differ from device to device

landscape,横屏

portrait,竖屏

user(用户当前设置的orientation值),The user's current preferred orientation

behind(下一个要显示的Activity的orientation值),The same orientation as the activity that's immediately beneath it in the activity stack

sensor(传 感器的方向),The orientation determined by a physical orientation sensor The orientation of the display depends on how the user is holding the device; it changes when the user rotates the device

nosensor(不 使用传感器,这个效果差不多等于unspecified)An orientation determined without reference to a physical orientation sensor The sensor is ignored, so the display will not rotate based on how the user moves the device Except for this distinction, the system chooses the orientation using the same policy as for the "unspecified" setting

3水平/垂直居中的方法

设置parent的android:gravity为"center"。

4获得当前屏幕宽高的方法

Display display = getWindowManager()getDefaultDisplay();

ConfigscreenWidth = displaygetWidth();

ConfigscreenHeight = displaygetHeight();

在Android界面的系统status bar上添加home,back,menu三个菜单,并完成对应的系统功能。并有higlight效果,修改status bar 高度和status bar上的文字尺寸。

这需要修改android sdk才能完成,我用的是eclair下面就我的 *** 作进行叙述。

1首先完成界面显示效果。

需要修改文件

/frameworks/base/services/java/com/android/server/status/StatusBarPolicyjava,仿照mBatteryIcon等icon的添加方式添加自定义的icon,名称指定就好了。另外还要记得修改/frameworks/base/core/res/res/values/arraysxml,这里定义了icon的slot,并且决定了icon的摆放顺序。

这样,你需要的icon按键就可以显示在系统的status bar上面了。

2判断touch event是否按动了某个icon

需要修改的文件

/frameworks/base/services/java/com/android/server/status/StatusBarViewjava

首先在onTouchEvent函数中,获取当前event的坐标,然后比较是否在某个按键范围之内。由于系统对于statusBar的范围已经有了定义,所以这里只需要比较横坐标就可以了。

其次,也是这一步最关键的,怎么获取具体某一个icon的左右边界坐标呢?系统的status bar左边显示的图标都是notification, 右边显示的是系统icon 也就是说左边icon属于mNotificationIcons,右边的icon属于mStatusIcons 在文件StatusBarViewjava中出现的offset = getViewOffset(mStatusIcons),得到mStatusIcons的最左边的icon的left横坐标。用N = mStatusIconsgetChildCount()得到共有几个系统icon,其中包含visibility为false的icons用mStatusIconsgetChildAt(N-i)得到的是从右边数第i个的icon view 这个view的getLeft()+offset就是这第i个icon的左边横坐标,对应的getRight()+offset就是这第i个icon的右边横坐标。本例中home键是右边第2个icon

3定义icon响应事件

这里使用的方法是在StatusBarViewjava中向

/frameworks/base/services/java/com/android/server/status/StatusBarPolicyjava发送一个Broadcast,让StatusBarPolicy来完成具体的事件 *** 作。这里需要注意的是不仅要在/frameworks/base/core/java/android/content/Intentjava中定义intent,还要在StatusBarPolicy的构造函数中添加该intent的过滤动作,即filteraddAction(IntentACTION_BACKICON_CHANGED)例如,按动了back键,如果当前事件为action_up,就向系统发送一个keyEvent,keyCode为KeyEventKEYCODE_BACK 这里借用的是/frameworks/base/cmds/input/src/com/android/commands/input/Inputjava中的sendKeyEvent函数,直接拷贝过来,按照需要稍微修改一下形参就可以了,过程不要修改。

需要说明的是,当点击statusBar可以拉出来一个notification列表,当这个列表显示出来的时候,这三个back, menu, home键的响应速度会非常慢,所以这时不响应事件并隐藏这三个键。具体做法是在StatusBarView的onTouchEvent()中判断mServicemExpanded或者 mServicemTracking为真时就不做响应。mService是StatusBarService对象。隐藏三个键也是用Broadcast来做的,但这个intent是由StatusBarServie发出来的,当mExpandedVisible = false时显示,当mExpandedVisible = true时隐藏。

这里还同时完成了highlight换图的动作,也是用Broadcast来做得,处理过程一样,就是需要区分action_down和action_up就可以了。

4调整status bar的高度

如果你需要显示较大的屏幕尺寸,同时statusBar的高度要拉大,上面的icon的size也需要调大。为了协调一致,显示时间的字体和notification显示的日期的字体也需要调大。具体做法如下:

a调节status bar icon的size: 只调节status_barxml的textSize标签似乎不起作用,同时又修改了/base/services/java/com/android/server/status/StatusBarIconjava的tsetTextSize(32);语句才成功。不知道修改status_barxml的<comandroidserverstatusAnimatedImageView>标签下的layout_height值是不是必须的,反正我是一起都给改了。

b调节status bar height: /base/core/res/res/values/dimensxml 找得我好辛苦!不知道还需不需要修改/base/core/res/res/values/themesxml中的Window attributes的windowTitleSize值,反正我也给改了。

c调节notification显示日期字体的大小,修改status_barxml的<comandroidserverstatusDateView>的textSize值。

到这里,就完成了所有工作,看看效果吧。

使用的ionic工程,重点是3,4方法;

找到了几种方法:

1、

报错:无法引入StatusBarManager

参考: >

定制系统的时候,想去掉系统中的状态栏,系统中的状态栏隐藏的可在framework中的SystemUIapk中修改实现。

SystemUIapk代码位于

RK2908/ics/frameworks/base/packages/SystemUI

设置状态栏不显示:

打开文件SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarjava

找到如下代码

460 final TabletStatusBarView sb = (TabletStatusBarView)Viewinflate(

461 context, Rlayoutstatus_bar, null);

462 mStatusBarView = sb;

在代码之后加入如下一行

mStatusBarViewsetVisibility(ViewINVISIBLE);

重新编译得到SystemUIapk

xiaxg@system:~/RK2908/ics/build$ source envsetupsh

xiaxg@system:~/RK2908/ics/frameworks/base/packages/SystemUI$ mm

得到的SystemUIapk 位于out/target/product/rk29sdk/system/app/SystemUIapk

布局文件所在/frameworks/base/packages/SystemUI/res/layout

status_bar_expanded_headerxml为下拉菜单中头部的布局文件,包括时间、日期、设置等。

status_bar_expandedxml 为下拉菜单整体布局

comAndroidsystemuistatusbar StatusBarIconView修改下拉菜单中icon布局

public StatusBarIconView(Context context, String slot, Notification notification) {

super(context);

final Resources res = contextgetResources();

mSlot = slot;

mNumberPain = new Paint();

mNumberPainsetTextAlign(PaintAlignCENTER);

mNumberPainsetColor(resgetColor(Rdrawablenotification_number_text_color));

mNumberPainsetAntiAlias(true);

mNotification = notification;

setContentDescription(notification);

// We do not resize and scale system icons (on the right), only notification icons (on the

// left)

if (notification != null) {

final int outerBounds = resgetDimensionPixelSize(Rdimenstatus_bar_icon_size);

final int imageBounds = resgetDimensionPixelSize(Rdimenstatus_bar_icon_drawing_size);

final float scale = (float)imageBounds / (float)outerBounds;

setScaleX(scale);

setScaleY(scale);

final float alpha = resgetFraction(Rdimenstatus_bar_icon_drawing_alpha, 1, 1);

setAlpha(alpha);

}

setScaleType(ImageViewScaleTypeCENTER_INSIDE);

}

以上就是关于如何Android中自定义Navigationbar全部的内容,包括:如何Android中自定义Navigationbar、android开发横竖屏问题、怎么样修改android源码等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9453133.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-28
下一篇 2023-04-28

发表评论

登录后才能评论

评论列表(0条)

保存