Android SystemUI之NavigationBar,导航栏(四) 您所在的位置:网站首页 底部导航条的功能介绍 Android SystemUI之NavigationBar,导航栏(四)

Android SystemUI之NavigationBar,导航栏(四)

2023-08-30 12:21| 来源: 网络整理| 查看: 265

Android  SystemUI系列:      1.Android  SystemUI之启动流程(一)      2.Android SystemUI之StatusBar,状态栏(二)      3.Android SystemUI之下拉菜单,通知栏,快捷面板(三)      4.Android SystemUI之NavigationBar,导航栏(四)      5.Android SystemUI之Recent,近期列表(五)   一、导航栏的创建      1.先上一幅导航栏的View结构图。如下。

    2.导航栏的创建

      StatusBar.makeStatusBarView

try { //创建导航栏 boolean showNav = mWindowManagerService.hasNavigationBar(); if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); if (showNav) { createNavigationBar(); } } catch (RemoteException ex) { // no window manager? good luck with that } protected void createNavigationBar() { mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> { mNavigationBar = (NavigationBarFragment) fragment; if (mLightBarController != null) { mNavigationBar.setLightBarController(mLightBarController); } mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility); }); }  NavigationBarFragment.create public static View create(Context context, FragmentListener listener) { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); lp.token = new Binder(); lp.setTitle("NavigationBar"); lp.accessibilityTitle = context.getString(R.string.nav_bar); lp.windowAnimations = 0; View navigationBarView = LayoutInflater.from(context).inflate( R.layout.navigation_bar_window, null); if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView); if (navigationBarView == null) return null; context.getSystemService(WindowManager.class).addView(navigationBarView, lp); FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView); NavigationBarFragment fragment = new NavigationBarFragment(); fragmentHost.getFragmentManager().beginTransaction() .replace(R.id.navigation_bar_frame, fragment, TAG) .commit(); fragmentHost.addTagListener(TAG, listener); return navigationBarView; }

上述代码做了两件事:1.创建navigationBarView 并且把navigationBarView添加到windowManager中。

                                 2.创建NavigationBarFragment 替换navigation_bar_window的布局文件,改成navigation_bar

navigation_bar.xml

我们先看NavigationBarInflaterView

public NavigationBarInflaterView(Context context, AttributeSet attrs) { super(context, attrs); createInflaters(); mDisplay = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); Mode displayMode = mDisplay.getMode(); isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight(); mOverviewProxyService = Dependency.get(OverviewProxyService.class); } private void createInflaters() { mLayoutInflater = LayoutInflater.from(mContext); Configuration landscape = new Configuration(); landscape.setTo(mContext.getResources().getConfiguration()); landscape.orientation = Configuration.ORIENTATION_LANDSCAPE; mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape)); } @Override protected void onFinishInflate() { super.onFinishInflate(); inflateChildren();//添加mRot0和mRot90,就是横竖屏的布局 clearViews();//清空所有的view inflateLayout(getDefaultLayout()); } private void inflateChildren() { removeAllViews(); mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false); mRot0.setId(R.id.rot0); addView(mRot0); mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this, false); mRot90.setId(R.id.rot90); addView(mRot90); updateAlternativeOrder(); }

上述代码就是在加载导航栏布局文件,如果是0度的时候加载navigation_layout,如果是90度的时候加载navigation_layout_rot90,横屏竖屏加载的layout不同。

protected void inflateLayout(String newLayout) { mCurrentLayout = newLayout; if (newLayout == null) { newLayout = getDefaultLayout(); } String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3); if (sets.length != 3) { Log.d(TAG, "Invalid layout."); newLayout = getDefaultLayout(); sets = newLayout.split(GRAVITY_SEPARATOR, 3); } String[] start = sets[0].split(BUTTON_SEPARATOR); String[] center = sets[1].split(BUTTON_SEPARATOR); String[] end = sets[2].split(BUTTON_SEPARATOR); // Inflate these in start to end order or accessibility traversal will be messed up. inflateButtons(start, mRot0.findViewById(R.id.ends_group), isRot0Landscape, true); inflateButtons(start, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, true); inflateButtons(center, mRot0.findViewById(R.id.center_group), isRot0Landscape, false); inflateButtons(center, mRot90.findViewById(R.id.center_group), !isRot0Landscape, false); addGravitySpacer(mRot0.findViewById(R.id.ends_group)); addGravitySpacer(mRot90.findViewById(R.id.ends_group)); inflateButtons(end, mRot0.findViewById(R.id.ends_group), isRot0Landscape, false); inflateButtons(end, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, false); updateButtonDispatchersCurrentView(); } protected String getDefaultLayout() { final int defaultResource = mOverviewProxyService.shouldShowSwipeUpUI() ? R.string.config_navBarLayoutQuickstep : R.string.config_navBarLayout; return mContext.getString(defaultResource); } protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape, boolean start) { LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater; View v = createView(buttonSpec, parent, inflater); if (v == null) return null; v = applySize(v, buttonSpec, landscape, start);//计算view的宽的大小 parent.addView(v); addToDispatchers(v); View lastView = landscape ? mLastLandscape : mLastPortrait; View accessibilityView = v; if (v instanceof ReverseRelativeLayout) { accessibilityView = ((ReverseRelativeLayout) v).getChildAt(0); } if (lastView != null) { accessibilityView.setAccessibilityTraversalAfter(lastView.getId()); } if (landscape) { mLastLandscape = accessibilityView; } else { mLastPortrait = accessibilityView; } return v; } private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) { View v = null; String button = extractButton(buttonSpec); if (LEFT.equals(button)) { String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE); button = extractButton(s); } else if (RIGHT.equals(button)) { String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE); button = extractButton(s); } // Let plugins go first so they can override a standard view if they want. for (NavBarButtonProvider provider : mPlugins) { v = provider.createView(buttonSpec, parent); if (v != null) return v; } if (HOME.equals(button)) { v = inflater.inflate(R.layout.home, parent, false); } else if (BACK.equals(button)) { v = inflater.inflate(R.layout.back, parent, false); } //laiyw add for volume Up/Down else if (VOLUME_DOWN.equals(button)) { v = inflater.inflate(R.layout.volume_down, parent, false); } else if (VOLUME_UP.equals(button)) { v = inflater.inflate(R.layout.volume_up, parent, false); //laiyw add for volume Up/Down } else if (RECENT.equals(button)) { v = inflater.inflate(R.layout.recent_apps, parent, false); } else if (MENU_IME_ROTATE.equals(button)) { v = inflater.inflate(R.layounu_ime, parent, false); } else if (NAVSPACE.equals(button)) { v = inflater.inflate(R.layout.nav_key_space, parent, false); } else if (CLIPBOARD.equals(button)) { v = inflater.inflate(R.layout.clipboard, parent, false); } else if (CONTEXTUAL.equals(button)) { v = inflater.inflate(R.layout.contextual, parent, false); } else if (button.startsWith(KEY)) { String uri = extractImage(button); int code = extractKeycode(button); v = inflater.inflate(R.layout.custom_key, parent, false); ((KeyButtonView) v).setCode(code); if (uri != null) { if (uri.contains(":")) { ((KeyButtonView) v).loadAsync(Icon.createWithContentUri(uri)); } else if (uri.contains("/")) { int index = uri.indexOf('/'); String pkg = uri.substring(0, index); int id = Integer.parseInt(uri.substring(index + 1)); ((KeyButtonView) v).loadAsync(Icon.createWithResource(pkg, id)); } } } return v; }

上述的代码都比较简单,有两点:

第一、导航栏显示哪些控件是由getDefaultLayout来决定。

left[.5W],back[1WC];home;recent[1WC],right[.5W]

一般情况下我们是home,recent,back这三个键,如果你需要加其他的就在这个配置文件夹。同时在createView添加对应的布局文件。

第二、createView方法创建对应的布局文件,并且添加到导航栏中。

home.xml

back.xml

recent_app.xml

那么我们现在布局文件都添加完成了,但是你会发现在NavigationBarInflaterView没有对资源文件添加的代码已经控件点击触摸事件处理逻辑。那么这两部分代码在哪里呢?

答案是:

1.NavigationBarView 完成资源文件添加。

2.NavigationBarFragment  添加点击事件和触摸事件的处理逻辑。

3.NavigationBarView public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); mDisplay = ((WindowManager) context.getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay(); mVertical = false; mShowMenu = false; mShowAccessibilityButton = false; mLongClickableAccessibilityButton = false; mOverviewProxyService = Dependency.get(OverviewProxyService.class); mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService); mConfiguration = new Configuration(); mConfiguration.updateFrom(context.getResources().getConfiguration()); M : New plugin architecture - Navigation bar plugin try { mSystemUICustomizationFactory = OpSystemUICustomizationFactoryBase.getOpFactory(context); mNavBarPlugin = mSystemUICustomizationFactory.makeNavigationBar(context); } catch (Exception e) { if (DEBUG) Log.d(TAG,"mNavBarPlugin init fail"); e.printStackTrace(); } reloadNavIcons();//初始化加载资源,主要是图片。 mBarTransitions = new NavigationBarTransitions(this); mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back)); mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home)); mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps)); mButtonDispatchers.put(R.id.volume_down, new ButtonDispatcher(R.id.volume_down)); mButtonDispatchers.put(R.id.volume_up, new ButtonDispatcher(R.id.volume_up)); getVolumeDownButton().setLongClickable(false); getVolumeUpButton().setLongClickable(false); mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu)); mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher)); mButtonDispatchers.put(R.id.accessibility_button, new ButtonDispatcher(R.id.accessibility_button)); mButtonDispatchers.put(R.id.rotate_suggestion, new ButtonDispatcher(R.id.rotate_suggestion)); mButtonDispatchers.put(R.id.menu_container, new ButtonDispatcher(R.id.menu_container)); mDeadZone = new DeadZone(this); } private void reloadNavIcons() { updateIcons(mContext, Configuration.EMPTY, mConfiguration); } private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) { int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme); int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme); Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme); Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme); if (oldConfig.orientation != newConfig.orientation || oldConfig.densityDpi != newConfig.densityDpi) { mDockedIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_docked); mHomeDefaultIcon = getHomeDrawable(lightContext, darkContext); } if (oldConfig.densityDpi != newConfig.densityDpi || oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) { Log.d("yangxiucheng", "oldConfig.densityDpi != newConfig.densityDpi"); mBackIcon = getBackDrawable(lightContext, darkContext); mRecentIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_recent); mMenuIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_menu); mAccessibilityIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_accessibility_button, false /* hasShadow */); //mImeIcon = getDrawable(lightContext, darkContext, R.drawable.ic_ime_switcher_default, //false /* hasShadow */); updateRotateSuggestionButtonStyle(mRotateBtnStyle, false); if (ALTERNATE_CAR_MODE_UI) { updateCarModeIcons(ctx); } } mVolumeDown = getDrawable(ctx,R.drawable.ic_sysbar_volume_down,R.drawable.ic_sysbar_volume_down_dark); mVolumeUp = getDrawable(ctx,R.drawable.ic_sysbar_volume_up,R.drawable.ic_sysbar_volume_up_dark); }

上述代码都比较简单,可以结合源码看一些细节,就不做太多说明

4.NavigationBarFragment public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mNavigationBarView = (NavigationBarView) view; mNavigationBarView.setDisabledFlags(mDisabledFlags1); mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel()); mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); mNavigationBarView.setOnTouchListener(this::onNavigationTouch); if (savedInstanceState != null) { mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState); } prepareNavigationBarView();//添加home ,recent触摸事件回调 checkNavBarModes(); setDisabled2Flags(mDisabledFlags2); IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_SWITCHED); getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); notifyNavigationBarScreenOn(); mOverviewProxyService.addCallback(mOverviewProxyListener); } private void prepareNavigationBarView() { mNavigationBarView.reorient(); //近期列表安静控制 ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton(); recentsButton.setOnClickListener(this::onRecentsClick); recentsButton.setOnTouchListener(this::onRecentsTouch); recentsButton.setLongClickable(true); recentsButton.setOnLongClickListener(this::onLongPressBackRecents); ButtonDispatcher backButton = mNavigationBarView.getBackButton(); backButton.setLongClickable(true); ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); homeButton.setOnTouchListener(this::onHomeTouch); homeButton.setOnLongClickListener(this::onHomeLongClick); ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton(); accessibilityButton.setOnClickListener(this::onAccessibilityClick); accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick); updateAccessibilityServicesState(mAccessibilityManager); ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton(); rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick); rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover); updateScreenPinningGestures(); }

上述代码中的setOnClickListener,setOnTouchListener,setLongClickable,setOnLongClickListener就是给对应的控件添加控制代码

到现在为止整个导航栏的View的添加,资源图片的加载,以及点击触摸事件的响应逻辑都讲了,其中还有一些细节,结合源码看应该不难,导航栏的讲解也就到此结束。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有