界面精确布局的探究

界面精确布局的探究

在多布局的时候会有这样的困扰,设置dp值使蒙层布局能够纹丝合缝的覆盖掉底层,但是宽屏手机如:魅族、华为荣耀,小屏手机如:oppo。总会出现覆盖的图“走位”。设置dp值只能使多数手机适配,下面的方法会让所有的手机都能适配。

实施步骤

  • 1 找到底层布局的left,top,由于get*()方法在sign控件界面加载出来前为零,咱们略作延迟,Handler post延迟时间为
    SystemClock.uptimeMillis()+delaytime

        new 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值