界面精确布局的探究
在多布局的时候会有这样的困扰,设置dp值使蒙层布局能够纹丝合缝的覆盖掉底层,但是宽屏手机如:魅族、华为荣耀,小屏手机如:oppo。总会出现覆盖的图“走位”。设置dp值只能使多数手机适配,下面的方法会让所有的手机都能适配。
实施步骤
1 找到底层布局的left,top,由于get*()方法在sign控件界面加载出来前为零,咱们略作延迟,Handler post延迟时间为
SystemClock.uptimeMillis()
+delaytimenew Handler().postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub sign.getLocationOnScreen(loaction); left = sign.getLeft(); top = sign.getTop(); right = sign.getRight(); bottom = sign.getBottom(); statusH = 60;//60为状态栏的高度,为了适配不同的手机,动态获取。demo中是在普通activity中拿的值。 signDialog = new SignGuideDialog(mActivity,R.layout.layout_guide_sign); signDialog.show(); //GuideControlUtil.getInstance(mActivity).setFinishShowSignGuide(); //signDialog.setDialogViewClick(this); } }, 100);
也可以在onWindowFocusChanged(boolean hasfocus)中得到这些值,不需要Handler。另外一种情况就是需要覆盖的View可能位置会被移动,再去执行sign.getLocationOnScreen(loaction);
得到的结果与之前没有移动的时候取得的值相同。这里面还包含状态栏的高度。在精确的计算中还得减去这部分。
解决的方法是,为该View添加监听
ViewTreeObserver vto = imageView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
imageView.getHeight();
imageView.getWidth();
imageView.getTop();
}
});
ViewTreeObserver是专门监听绘图回调的,我们在每次监听前remove前一次的监听,避免重复监听。
2 将left,top传给蒙层,设置蒙层的layoutparams。
public void initLayout(){ ImageView imgRect = (ImageView) findViewById(R.id.guide_sign); int left = UnLoginSignDialog.left; int right = UnLoginSignDialog.right; int top = UnLoginSignDialog.top; int bottom = UnLoginSignDialog.bottom; int[] loaction = UnLoginSignDialog.loaction; LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(right-left, bottom-top); //当然也可以用imgRect.getLayoutParams得到布局文件中的属性,修改部分属性后,imgRect.setLayoutParams params.leftMargin = loaction[0]; params.topMargin = loaction[1]-UnLoginSignDialog.statusH; imgRect.setLayoutParams(params); }
延伸扩展
得到状态栏高度
private int getStatusLayerHeight(){
Rect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
return statusBarHeight;
}
得到标题栏高度
private void getTitleLayerHeight(){
int contentTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
//statusBarHeight是上面所求的状态栏的高度
int titleBarHeight = contentTop - getStatusLayerHeight();
}
得到全屏高度
private static DisplayMetrics sDisplayMetrics;
public static void init(Context context) {
sDisplayMetrics = context.getResources().getDisplayMetrics();
checkScreen();
}
/**
* 获取屏幕宽度 单位:像素
*
* @return 屏幕宽度
*/
public static int getWidthPixels() {
return sDisplayMetrics.widthPixels;
}
/**
* dp 转 px
*
* @param dp dp值
* @return 转换后的像素值
*/
public static int dp2px(int dp) {
return (int) (dp * sDisplayMetrics.density + ROUND_DIFFERENCE);
}
/**
* dp 转 px
*
* @param dp dp值
* @return 转换后的像素值
*/
public static float dp2px(float dp) {
return dp * sDisplayMetrics.density + ROUND_DIFFERENCE;
}
/**
* px 转 dp
*
* @param px px值
* @return 转换后的dp值
*/
public static int px2dp(int px) {
return (int) (px / sDisplayMetrics.density + ROUND_DIFFERENCE);
}
许多手机有NavigationBar,有些是在屏幕下方,有些是在实体键盘中,这部分也会算入屏幕大小。这样会造成布局控件在onMeasure()方法操作有误差。故需要判断是否存在,如果存在那么高度几何
是否存在NavigationBar
private static boolean checkDeviceHasNavigationBar(Context context) {
boolean hasNavigationBar = false;
Resources rs = context.getResources();
int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
hasNavigationBar = rs.getBoolean(id);
}
try {
Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
Method m = systemPropertiesClass.getMethod("get", String.class);
String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
if ("1".equals(navBarOverride)) {
hasNavigationBar = false;
} else if ("0".equals(navBarOverride)) {
hasNavigationBar = true;
}
} catch (Exception e) {
Log.w(TAG, e);
}
return hasNavigationBar;
}
- 获取NavigationBar的高
private static int getNavigationBarHeight(Context context) {
int navigationBarHeight = 0;
Resources rs = context.getResources();
int id = rs.getIdentifier("navigation_bar_height", "dimen", "android");
if (id > 0 && checkDeviceHasNavigationBar(context)) {
navigationBarHeight = rs.getDimensionPixelSize(id);
}
return navigationBarHeight;
}
7/2/2015 9:26:41 AM