在输入法开发中解决Android P下导航栏出现黑条的问题,并介绍Xamarin.Android下的一个坑

自Android P发布以来,陆陆续续的有用户向我反映Android P下输入法存在导航栏变黑的问题,情况如下所示。


用户提供的效果图

于是我抽时间研究了一下这个问题。
经过一番搜索,我在Simple Keyboard下找到了解决方案,其代码大致如下:

  private int mOriginalNavBarColor = 0;
  private int mOriginalNavBarFlags = 0;
  ......

 private void setNavigationBarColor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
             ......
            final Window window = getWindow().getWindow();
            if (window == null) {
                return;
            }
            mOriginalNavBarColor = window.getNavigationBarColor();
            window.setNavigationBarColor(keyboardColor);

            final View view = window.getDecorView();

            mOriginalNavBarFlags = view.getSystemUiVisibility();
            if (ResourceUtils.isBrightColor(keyboardColor)) {
                view.setSystemUiVisibility(mOriginalNavBarFlags | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
            } else {
                view.setSystemUiVisibility(mOriginalNavBarFlags & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
            }
        }
    }

    private void clearNavigationBarColor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            final Window window = getWindow().getWindow();
            if (window == null) {
                return;
            }
            window.setNavigationBarColor(mOriginalNavBarColor);
            final View view = window.getDecorView();
            view.setSystemUiVisibility(mOriginalNavBarFlags);
        }
    }

具体的原理,我也不班门弄斧了,想要深入了解的同学请自行百度(代码中的ResourceUtils.isBrightColor实现,我在后面的C#代码中给出)。而因为我使用Xamarin开发的岁寒输入法,所以不能简单地Ctrl+V、Ctrl+C,需要将其转写成C#代码,说白了,就是抄。但这一抄,抄出了大问题。

Xamarin.Android会对Android的原生API进行二次封装,一般而言,get/set方法会转换成属性,flag值会封装成枚举型。
在这个场景下,具体就是:

View.getSystemUiVisibility()/View.setSystemUiVisibility(int) =>StatusBarVisibility View.SystemUiVisibility {get;set;}

其中StatusBarVisibility就是setSystemUiVisibility所能接受的flag值的封装。然而这里出现了错误!
setSystemUiVisibility方法所能接受flag值如下图:

而StatusBarVisibility的内容是这样的:

显然,这两者是对不上的。
经过研究,我发现有另一个枚举类型——SystemUiFlags,他的内容是这样的:

显而易见,SystemUiFlags正是对setSystemUiVisibility方法所能接受的flag值的正确封装。可是为什么 View.SystemUiVisibility的类型会是StatusBarVisibility呢?

我在Xamarin.Android的GitHub项目的下发现了一些相关的issue,才确认,这确实是Xamarin.Android的的封装错误,而且年代久远,因为无法修复。这里有bugzilla上的bug反馈记录
从bug记录中的官方回复可知,如果对这个问题进行更正,会破坏Xamarin.Android的二进制接口(ABI)。

官方如此解释这种破坏的原因:

所以这个封装错误将不会得到修正,只能将错就错。

如此一来,难道这个接口就不能用了吗?倒也不是。
官方有云:
The fact that the type is an enum is *irrelevant*. The fact that values of the type can be cast to other types is irrelevant. What matters are the actual types, as contained in the assembly: System.StringComparison != System.TypeCode. (Note in particular that both StringComparison and TypeCode are enumeration types withintas the underlying enum type.)
简单而言就是,枚举型本质上还是int型,对其进行强制类型转换不会改变其本质。所以,解决方案就是在适当的时候使用强制类型转换来解决问题,虽然代码会因此看上去有点丑。

        int originalNavBarColor;
        int originalNavBarFlags;
        private void setNavigationBarColor() {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.P) {
                Window window = this.Window.Window;
                if (window == null) return;
                originalNavBarColor = window.NavigationBarColor;
                
                window.SetNavigationBarColor(newColor);
                var view = window.DecorView;
                originalNavBarFlags = (int)view.SystemUiVisibility;
                if (isBrightColor(color)) {
                    view.SystemUiVisibility = (StatusBarVisibility)(originalNavBarFlags | (int)SystemUiFlags.LightNavigationBar);
                } else {
                    view.SystemUiVisibility = (StatusBarVisibility)(originalNavBarFlags & ~(int)SystemUiFlags.LightNavigationBar);
                }
            }
        }

        private void clearNavigationBarColor() {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.P) {
                Window window = this.Window.Window;
                if (window == null) return;
                window.SetNavigationBarColor(new Color(originalNavBarColor));
                window.DecorView.SystemUiVisibility = (StatusBarVisibility)originalNavBarFlags;
            }
        }

        static bool isBrightColor(int color) {
            if (Android.Resource.Color.Transparent == color) {
                return true;
            }
            // See http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
            bool bright = false;
            int[] rgb = { Color.GetRedComponent(color), Color.GetGreenComponent(color), Color.GetBlueComponent(color) };
            int brightness = (int)Math.Sqrt(rgb[0] * rgb[0] * .241 + rgb[1] * rgb[1] * .691 + rgb[2] * rgb[2] * .068);
            if (brightness >= 210) {
                bright = true;
            }
            return bright;
        }

以上。

希望本文能对你有所帮助,感谢阅读。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容