分享功能在实际项目开发中经常用到的,有可能是在屏幕中间弹出的 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();
} }
你觉得有问题吗?我觉得没问题,因为在项目中使用了几个版本了,还经过测试的,肯定没问题,但是看下面的效果图
不仔细看也没有问题啊,再看下,是不是“取消”按钮没啦,是不是屏幕下面多出一个 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了,效果图如下
解决办法参考:http://blog.csdn.net/lnb333666/article/details/41821149