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手機上截圖
解決辦法參考:http://blog.csdn.net/lnb333666/article/details/41821149
孫福生的微信公眾號