前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android屏幕适配框架(一)

Android屏幕适配框架(一)

作者头像
aruba
发布2020-07-03 10:44:03
7940
发布2020-07-03 10:44:03
举报
文章被收录于专栏:android技术
核心思路:利用ui设计稿的尺寸和手机自身尺寸得出缩放比,再将控件宽高处理后设置到控件上。性能方面会多渲染一次控件
ui设计稿高和宽这边假设是1920*1080,具体根据实际设计稿来设置
代码语言:javascript
复制
//ui图上的宽高
private static final int BASE_WIDTH = 1080;
private static final int BASE_HEIGHT = 1920; // ui给的图不包含状态栏,后面要减去状态栏的高度
定义一些变量
代码语言:javascript
复制
//设备的真实宽高
private static int displayWidth;
private static int displayHeight; // 后面要减去状态栏的高度
//状态栏高度
private int statusBarHeight;
//屏幕信息
private DisplayMetrics displayMetrics;
首先使用WindowManager获取本机屏幕长宽,存放在displayMetrics.widthPixels 和 displayMetrics.heightPixels中
代码语言:javascript
复制
  WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  displayMetrics = new DisplayMetrics();
  windowManager.getDefaultDisplay().getMetrics(displayMetrics);
而实际屏幕大小要减去状态栏高度,这边需要获取下状态栏高度
代码语言:javascript
复制
   //使用运行过程中的资源文件
    private int getStatusBarHeight(Context context) {
        int statusBarHeight = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (statusBarHeight > 0) {
            return statusBarHeight;
        }

        //上面方法获取不到的话,使用反射资源获取
        return getStatusBarHeightByAndroid(context, "com.android.internal.R$dimen", "system_bar_height", 48);
    }

    private int getStatusBarHeightByAndroid(Context context, String className, String fieldName, int defValue) {
        try {
            //获取class
            Class aClass = Class.forName(className);
            //获取实例
            Object o = aClass.newInstance();
            Field field = aClass.getField(fieldName);
            int id = Integer.parseInt(field.get(o).toString());
            return context.getResources().getDimensionPixelOffset(id);
        } catch (Exception e) {
            return defValue;
        }
    }
根据是否横竖屏设置真实高度
代码语言:javascript
复制
    /**
     * 设置真实长宽
     */
    public void refreshDisplayMetrics() {
        //判断横竖屏
        if (displayMetrics.widthPixels > displayMetrics.heightPixels) {//横屏
            displayWidth = displayMetrics.heightPixels;
            displayHeight = displayMetrics.widthPixels;
        } else { //竖屏
            displayWidth = displayMetrics.widthPixels;
            displayHeight = displayMetrics.heightPixels;
        }
    }
至此初始化函数代码为下:
代码语言:javascript
复制
    //初始化真实宽高
    public void init(Context context) {
        //使用WindowManager获取
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);

        //获取状态栏高度
        statusBarHeight = getStatusBarHeight(context);
        //根据状态栏高度初始化真实宽高
        refreshDisplayMetrics();
    }
再写两个获取处理后的宽和高的方法,高度计算时需减去状态栏高度
代码语言:javascript
复制
    public float getWidth(float width) {
        return width * displayWidth / BASE_WIDTH;
    }

    public float getHeight(float height) {
        return height * (displayHeight - statusBarHeight) / (BASE_HEIGHT - statusBarHeight);
    }
主要核心代码已完成,再将对控件的逻辑处理完成
代码语言:javascript
复制
/**
 * view设置长宽等属性的逻辑处理
 * 需使用px
 */
public class ViewCalculateUtil {
    /**
     * 设置layoutparams
     *
     * @param view
     * @param width
     * @param height
     * @param topMargin
     * @param bottomMargin
     * @param leftMargin
     * @param rightMargin
     */
    public static void setLayoutParams(View view, int width, int height, int topMargin, int bottomMargin, int leftMargin, int rightMargin) {
        ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();

        if (layoutParams != null) {

            if (width != LinearLayout.LayoutParams.MATCH_PARENT &&
                    width != LinearLayout.LayoutParams.WRAP_CONTENT) {
                layoutParams.width = (int) UIUtils.getInstance().getWidth(width);
            } else {
                layoutParams.width = width;
            }

            if (height != LinearLayout.LayoutParams.MATCH_PARENT && height != LinearLayout.LayoutParams.WRAP_CONTENT) {
                layoutParams.height = (int) UIUtils.getInstance().getHeight(height);
            } else {
                layoutParams.height = height;
            }

            layoutParams.topMargin = (int) UIUtils.getInstance().getHeight(topMargin);
            layoutParams.bottomMargin = (int) UIUtils.getInstance().getHeight(bottomMargin);
            layoutParams.leftMargin = (int) UIUtils.getInstance().getWidth(leftMargin);
            layoutParams.rightMargin = (int) UIUtils.getInstance().getWidth(rightMargin);
            view.setLayoutParams(layoutParams);
        }
    }

    /**
     * 设置字号
     *
     * @param view
     * @param size
     */
    public static void setTextSize(TextView view, int size) {
        view.setTextSize(TypedValue.COMPLEX_UNIT_PX, UIUtils.getInstance().getHeight(size));
    }

    /**
     * 设置view的内边距
     *
     * @param view
     * @param topPadding
     * @param bottomPadding
     * @param leftpadding
     * @param rightPadding
     */
    public static void setViewPadding(View view, int topPadding, int bottomPadding, int leftpadding, int rightPadding) {
        view.setPadding((int) UIUtils.getInstance().getWidth(leftpadding),
                (int) UIUtils.getInstance().getHeight(topPadding),
                (int) UIUtils.getInstance().getWidth(rightPadding),
                (int) UIUtils.getInstance().getHeight(bottomPadding));
    }
}
可以使用上面工具类中的方法对单个控件进行适配,但我们不希望每个控件都要写一行代码,再进行封装得出下面的类:
代码语言:javascript
复制
/**
 * 逐层处理viewgroup
 */
public class ViewsParseUtil {

    /**
     * 对activity中的所有控件进行适配
     * @param activity
     */
    protected static void parseAcitvity(Activity activity) {
        //获取DecorView中id为content的布局
        final ViewGroup context = (ViewGroup) activity.findViewById(android.R.id.content);
        context.post(new Runnable() {
            @Override
            public void run() {
                catchViewGroup(context);
            }
        });
    }

    /**
     * 对组件进行适配
     * @param viewGroup
     */
    protected static void catchViewGroup(ViewGroup viewGroup) {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View view = viewGroup.getChildAt(i);
            catchChildView(view);
        }
    }

    /**
     * 对控件进行适配
     * @param view
     */
    private static void catchChildView(View view) {
        if (view instanceof ViewGroup) {
            catchViewGroup((ViewGroup) view);
        } else {
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();

            //设置LayoutParams
            ViewCalculateUtil.setLayoutParams(view, layoutParams.width, layoutParams.height, layoutParams.topMargin, layoutParams.bottomMargin,
                    layoutParams.leftMargin, layoutParams.rightMargin);
            if (view instanceof TextView) {//如果是textview,设配字体大小
                TextView textView = (TextView) view;
                ViewCalculateUtil.setTextSize(textView, (int) textView.getTextSize());
            }
            //设置padding
            ViewCalculateUtil.setViewPadding(view, view.getPaddingTop(), view.getPaddingBottom(), view.getPaddingLeft(), view.getPaddingRight());
        }
    }

}
最后使用方法,在合适的地方初始化框架
代码语言:javascript
复制
UIUtils.getInstance().init(getApplicationContext());
在activity中调用
代码语言:javascript
复制
UIUtils.getInstance().registerActivity(this);
项目地址https://gitee.com/aruba/ScreenAdapter.git
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 核心思路:利用ui设计稿的尺寸和手机自身尺寸得出缩放比,再将控件宽高处理后设置到控件上。性能方面会多渲染一次控件
    • ui设计稿高和宽这边假设是1920*1080,具体根据实际设计稿来设置
      • 定义一些变量
        • 首先使用WindowManager获取本机屏幕长宽,存放在displayMetrics.widthPixels 和 displayMetrics.heightPixels中
          • 而实际屏幕大小要减去状态栏高度,这边需要获取下状态栏高度
            • 根据是否横竖屏设置真实高度
              • 至此初始化函数代码为下:
                • 再写两个获取处理后的宽和高的方法,高度计算时需减去状态栏高度
                  • 主要核心代码已完成,再将对控件的逻辑处理完成
                    • 可以使用上面工具类中的方法对单个控件进行适配,但我们不希望每个控件都要写一行代码,再进行封装得出下面的类:
                    • 最后使用方法,在合适的地方初始化框架
                    • 在activity中调用
                    • 项目地址https://gitee.com/aruba/ScreenAdapter.git
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档