美文网首页ITBOXAndroidAndroid资源收录
自定义 ShareView 之 NavigationBar 适配

自定义 ShareView 之 NavigationBar 适配

作者: 孙福生微博 | 来源:发表于2016-08-01 10:22 被阅读2239次
ShareView

分享功能在实际项目开发中经常用到的,有可能是在屏幕中间弹出的 Dialog 对话框,也有可能是从屏幕下方滑上来的视图。本文是自定义从屏幕下方滑上来的分享控件,将 ShareView add 到 DecorView 上,但是在带 NavigationBar 导航条的手机上出现适配问题,下面是我碰到的问题及解决方法。

小米手机上截图

这个功能如何实现的呢?贴下主要代码(具体参考GitHub上项目)。

public class ShareView {

    private Activity mActivity;
    private View fullMaskView; // 蒙层视图
    private View contentLayout; // 分享视图
    private int panelHeight = 0; // 分享视图高度

    public ShareView(Activity activity) {
        this.mActivity = activity;
        initShareView(activity);
    }

    private void initShareView(Activity activity) {
        fullMaskView = View.inflate(activity, R.layout.ui_view_full_mask_layout, null);
        contentLayout = LayoutInflater.from(activity).inflate(R.layout.ui_share, null);
        ButterKnife.bind(this, contentLayout);

        attachView();
        initListener();
    }

    // 将该View添加到根布局
    private void attachView() {
        ((ViewGroup) mActivity.getWindow().getDecorView()).addView(fullMaskView);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        params.gravity = Gravity.BOTTOM;
        ((ViewGroup) mActivity.getWindow().getDecorView()).addView(contentLayout, params);
        fullMaskView.setVisibility(View.GONE);
        contentLayout.setVisibility(View.GONE);
    }

    // 动画显示布局
    public void show() {
        fullMaskView.setVisibility(View.VISIBLE);
        contentLayout.setVisibility(View.VISIBLE);
        contentLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                contentLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                ViewGroup parent = (ViewGroup) contentLayout.getParent();
                panelHeight = parent.getHeight() - contentLayout.getTop();
                ObjectAnimator.ofFloat(contentLayout, "translationY", panelHeight, 0).setDuration(200).start();
            }
        });
    }

    // 动画隐藏布局
    public void hide() {
        fullMaskView.setVisibility(View.GONE);
        ObjectAnimator.ofFloat(contentLayout, "translationY", 0, panelHeight).setDuration(200).start();
    }

}

你觉得有问题吗?我觉得没问题,因为在项目中使用了几个版本了,还经过测试的,肯定没问题,但是看下面的效果图

华为Nexus手机上截图

不仔细看也没有问题啊,再看下,是不是“取消”按钮没啦,是不是屏幕下面多出一个 NavigationBar 的条目呢。

so, that`s the problem !

上面这张图是在华为 Nexus 手机上截的图,这么一来这个自定义 ShareView 在所有屏幕底下带有 NavigationBar 的手机上都会有问题,经过测试,确实是这样的,虽然对于整体功能没有太大影响,但是仍不可以忍受。

我们使用的大多数 Android 手机上的Home键,返回键以及menu键都是实体触摸感应按键,但是,一些手机生厂商包括 Google 在内它们并没有实体按键或触摸感应按键,取而代之的是在屏幕的下方加上 NavigationBar 导航条,我是很吐糟这种设计的,虽然这使得手机外观的设计更加简约。

找到原因就是找到解决办法了,先获取手机是否有导航条,有则在显示和隐藏动画的时候多加上导航条的高度

private int navigationBarHeight = 0; // 导航栏高度

// 将该View添加到根布局
private void attachView() {
    // ...
    if (hasNavigationBar(mActivity)) {
        navigationBarHeight = getNavigationBarHeight(mActivity);
    }
}

// 动画显示布局
public void show() {
    // ...
    ObjectAnimator.ofFloat(contentLayout, "translationY", panelHeight, -navigationBarHeight).setDuration(200).start();
}

// 动画隐藏布局
public void hide() {
    // ...
    ObjectAnimator.ofFloat(contentLayout, "translationY", -navigationBarHeight, panelHeight).setDuration(200).start();
}

// 判断设备是否有返回键、菜单键来确定是否有 NavigationBar
public static boolean hasNavigationBar(Context context) {
    boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
    boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
    if (!hasMenuKey && !hasBackKey) {
        return true;
    }
    return false;
}

// 获取 NavigationBar 的高度
public static int getNavigationBarHeight(Activity activity) {
    Resources resources = activity.getResources();
    int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
    return resources.getDimensionPixelSize(resourceId);
}

这样就OK了,效果图如下

华为Nexus手机上截图

具体参考GitHub上项目

解决办法参考:http://blog.csdn.net/lnb333666/article/details/41821149

孙福生的微信公众号

关于我

个人邮箱:sfsheng0322@126.com
GitHub主页
简书主页
个人博客
新浪微博

相关文章

网友评论

  • Tauruse:博主你好,运行了你的In-depthStudy程序,想问一下com.sun.study.framework.base中的这些文件是用来干嘛的?从BaseActivity继承BaseAsyncActivity,再到BaseControl,再到BaseHelper。具体是在什么样的场景下会使用到这里面的方法呢?
  • hackware:你这个东西,用一个对话框不可以么,gravity设置为bottom,也没有这个问题啊
  • hackware:根本就不需要适配嘛,是你的布局方式有问题。
    cuixbo:@hackware 你试过吗?他已经用bottom了,还是framelayout
    hackware:@孙福生微博 呵呵,这要看你怎么布局了,你从上往下布局,视图多半会在带虚拟键的手机上被切掉,如果你从下往上布局,就没这个问题
    孙福生微博: @hackware 看来你不懂这种实现方式嘛
  • f988b2f0d95c:在不 ,git引入你的项目 学习一下出现 运行 Error:Execution failed for task ':app:validateReleaseSigning'.
    > Keystore file E:\Documents\In-depthStudy\app\Users\sunfusheng\Android\keystore\app_keystore.jks not found for signing config 'release'. 求解决一下
    f988b2f0d95c:@孙福生微博 谢谢 我试一下
    mlick:@f988b2f0d95c
    signingConfigs {
    release {
    storeFile file(prop['KEYSTORE_FILEPATH'])
    storePassword prop['STORE_PASSWORD']
    keyAlias prop['KEY_ALIAS']
    keyPassword prop['KEY_PASSWORD']
    }
    }
    可以把这几行干掉
    孙福生微博: @f988b2f0d95c 签名文件我上传了,你把路径改一下
  • mlick:楼主魅族手机有测试么,
    小白龙vip:@mlick 那么你可以试试。不过4都全面升级flayme 5了。 我觉得不用考虑了。因为去年魅族已经抛弃了。除非你们的用户比较广。你可以试试咯。
    mlick:@小白龙vip 对呀,我有次程序单独对魅族3还是4手机做过处理,很恶心的
    小白龙vip:@mlick 魅族很早的版本吧。Flayme4就饿没有了。

本文标题:自定义 ShareView 之 NavigationBar 适配

本文链接:https://www.haomeiwen.com/subject/rnuxsttx.html