根据设备调整组件

问题描述 投票:2回答:1

是否有一种方法可以根据要安装该应用的设备的大小来调整容器和字体大小?我已经开发了一个应用程序,并在我的手机(三星S8 +)上以我希望它出现的方式出现。当我将其安装在屏幕较小的手机上时,布局发生了变化,组件在小型手机上显得很大。

Small phone (Tecno)Samsung S8+

该页面的CSS代码是:

Login-TextFields{
    font-size: 3mm;
    margin: 0.5mm 1mm 0mm 1mm;
    padding: 1mm;
    color: white;
    background: transparent;
    padding: 0mm 0mm 0mm 0mm;
}

Login-Field-Container{
    border: none;
    border-bottom: 0.25mm solid white;
    padding-top: 5mm;
}
LoginFields-Container {
    width: auto;
    height: 2mm;
    border-radius: 3mm;
    padding-top: 8mm;
    margin: 7mm 2mm 0mm 2mm;
    background-color: transparent;
}
LoginForm-Background{
    background-image: url(../assets/background.jpg);
    cn1-background-type: cn1-image-scaled-fill;
    padding: 5mm;
}
Logo-Container{
    background: none;
}
Mask-Button{
    color: white;
}
Login-Button {
    background-color: #0052cc;
    border-radius: 3mm;
    border: none;
    padding: 1mm 2mm 1mm 2mm;
    color: white;
    font-size: 3mm;
    text-align: center;
    margin: 2mm 3mm 2mm 3mm;
}
Forgot-Button{
    text-align: right;
    color: white;
    font-style: italic;
    font-size: 2.5mm;
    margin: 0px;
}
SignUp-Button{
    color: white;
    margin: 1mm 2mm 1mm 0mm;
    text-align: right; 
}
Dont-Have-Account-Label{
    color: #ccffff;
    margin: 1mm 2mm 1mm 0mm;
    text-align: center; 
}
Logo-Area{
    padding: 1mm;
    margin: 2mm 3mm 2mm 3mm;
    text-align: center;
}
Copyright{
    color: white;
}

我想在所有设备上的第二个图像中保持布局。我希望容纳这些字段的容器在保持布局和比例的同时根据设备进行调整。

codenameone
1个回答
1
投票

根据注释Adjust components basing on devices中的要求,首先将以下Java类添加到您的项目中。它包含的内容超出了您的需要,您可以根据需要自定义它。最重要的是一行:int defaultScreenWidth = Display.getInstance().convertToPixels(70);。它是不言自明的:它指示参考尺寸,在这种情况下为70mm。

import com.codename1.io.Log;
import com.codename1.ui.CN;
import com.codename1.ui.Display;
import com.codename1.ui.Font;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

/**
 *
 *
 */
public class CSSUtilities {

    // Note: we assume that the only target platforms are native iOS, native Android and Javascript
    public static final boolean isAndroidTheme = UIManager.getInstance().isThemeConstant("textComponentOnTopBool", false);
    public static final boolean isIOSTheme = !isAndroidTheme;

    private static int percentage = calculateAdaptionPercentage();

    /**
     * Call this method if you need to recalculate the adapting percentage
     */
    public static int recalculatePercentage() {
        percentage = calculateAdaptionPercentage();
        return percentage;
    }

    /**
     * Load multiple CSSes, note that "iOS" css is loaded only if the native iOS
     * theme is used, the "Android" css is loaded only if the native Android
     * theme is used, the "WebApp" css is loaded only if the app is running on
     * Javascript; for info about build.xml:
     * https://stackoverflow.com/questions/53480459/multiple-codename-one-css
     *
     * @param css file names, WITHOUT SLASHES AND WITHOUT .css EXTENSION!!!
     */
    public static void loadMultipleCSSes(String... css) {
        try {
            UIManager.initFirstTheme("/" + css[0]);
            Resources resource = Resources.openLayered("/" + css[0]);
            UIManager.getInstance().setThemeProps(adaptTheme(resource.getTheme("Theme")));
            Resources.setGlobalResources(resource);

            Log.p("Loaded " + css[0] + ".css", Log.DEBUG);
            if (isIOSTheme) {
                Log.p("The currently used native theme is iOS", Log.DEBUG);
            }
            if (isAndroidTheme) {
                Log.p("The currently used native theme is Android", Log.DEBUG);
            }

            for (int i = 1; i < css.length; i++) {
                if (css[i].equals("iOS")) {
                    if (!isIOSTheme) {
                        continue;
                    } else {
                        Log.p("Loading CSS for iOS native theme only", Log.DEBUG);
                    }
                }
                if (css[i].equals("Android")) {
                    if (!isAndroidTheme) {
                        continue;
                    } else {
                        Log.p("Loading CSS for Android native theme only", Log.DEBUG);
                    }
                }
                if (css[i].equals("WebApp")) {
                    if (!isJavascript()) {
                        continue;
                    } else {
                        Log.p("Loading CSS for web-app only", Log.DEBUG);
                    }
                }
                Resources res = Resources.openLayered("/" + css[i]);
                if (!css[i].equals("MyController")) {
                    UIManager.getInstance().addThemeProps(adaptTheme(res.getTheme("Theme")));
                } else {
                    UIManager.getInstance().addThemeProps(res.getTheme("Theme"));
                }
                Log.p("Loaded " + css[i] + ".css", Log.DEBUG);
            }
            // Log.p("CssUtilities.loadMultipleCSSes - success, loaded in the order: " + css.toString(), Log.INFO);
        } catch (Exception ex) {
            Log.p("CssUtilities.loadMultipleCSSes - ERROR", Log.ERROR);
            Log.e(ex);
            Log.sendLogAsync();
        }
    }

    /**
     * Calculate the percentage to adapt the font sizes to the screen width. The
     * maximum decrease of the sizes is about 30%, increasing is disabled.
     *
     * @return percentage from -30 to 0
     */
    private static int calculateAdaptionPercentage() {
        int defaultScreenWidth = Display.getInstance().convertToPixels(70);
        int currentScreenWidth = Display.getInstance().getDisplayWidth();
        int currentInMM = currentScreenWidth / Display.getInstance().convertToPixels(1);

        int percentage = currentScreenWidth * 100 / defaultScreenWidth - 100;
        if (percentage < -30) {
            percentage = -30;
        } else if (percentage > 0) {
            percentage = 0;
        }

        Log.p("Estimated screen width: " + currentInMM + " mm", Log.INFO);
        Log.p("Font percentage: " + percentage + "%", Log.INFO);
        return percentage;
    }

    /**
     * Modify a theme changing the font sizes, margins and paddings
     *
     * @param themeProps
     * @return the new theme
     */
    private static Hashtable adaptTheme(Hashtable hashtable) {
        Hashtable<String, Object> result = new Hashtable<>();
        Set<String> keys = hashtable.keySet();
        Iterator<String> itr = keys.iterator();
        String key;
        Object value;
        while (itr.hasNext()) {
            key = itr.next();
            value = hashtable.get(key);
            // Log.p("key: " + key + ", value is: " + value.getClass().getName() + ", " + value.toString());
            if (value instanceof Font && ((Font) value).isTTFNativeFont() && percentage < 0) {
                Font font = (Font) value;
                float newSize = (int) (font.getPixelSize() * (100 + percentage) / 100);
                result.put(key, font.derive(newSize, font.getStyle()));
            } else if (key.endsWith("#margin") || key.endsWith(".margin")
                    || key.endsWith("#padding") || key.endsWith(".padding")) {
                if (value instanceof String) {
                    // Log.p("input:  " + value);
                    // Log.p("output: " + resizeMarginPadding((String) value));
                    result.put(key, resizeMarginPadding((String) value));
                }
            } else {
                result.put(key, value);
            }
        }
        return result;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @return
     */
    public static int getResized(int size) {
        return size * (100 + percentage) / 100;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @return
     */
    public static float getResized(double size) {
        return (float) (size * (100 + percentage) / 100);
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @param convertToPx if true, convert the given size from mm to pixels
     * @return
     */
    public static int getResized(int size, boolean convertToPx) {
        if (!convertToPx) {
            return getResized(size);
        } else {
            return getResized(Display.getInstance().convertToPixels(size));
        }
    }

    /**
     * Resizes the given margin or the padding
     *
     * @param input in a form like 0.0,1.0,0.9,15.0
     * @return the given input if it's not a valid margin or padding, or a new
     * String with the margins or paddings recalculated
     */
    private static String resizeMarginPadding(String input) {
        String result = "";

        StringTokenizer st = new StringTokenizer(input, ",");
        // Do we have 4 numbers?
        if (st.countTokens() == 4) {
            while (st.hasMoreTokens()) {
                // Is this token a number like 1.5, 0.0, etc.?
                String token = st.nextToken();
                try {
                    Float number = Float.valueOf(token);
                    number = getResized(number);
                    number = ((int) (number * 10)) / 10.0f;
                    result += number;
                    if (st.countTokens() != 0) {
                        result += ",";
                    }
                } catch (NumberFormatException e) {
                    return input;
                }
            }
        } else {
            return input;
        }

        return result;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @param convertToPx if true, convert the given size from mm to pixels
     * @return
     */
    public static double getResized(double size, boolean convertToPx) {
        if (!convertToPx) {
            return getResized(size);
        } else {
            return getResized(Display.getInstance().convertToPixels((float) size));
        }
    }

    /**
     * Returns true if the app is running in the CN1 Simulator
     *
     * @return
     */
    public static boolean isSimulator() {
        return Display.getInstance().isSimulator();
    }

    /**
     * Returns true if the app is running as native Android app
     *
     * @return
     */
    public static boolean isAndroidNative() {
        return !isSimulator() && "and".equals(CN.getPlatformName());
    }

    /**
     * Returns true if the app is running as native iOS app
     *
     * @return
     */
    public static boolean isiOSNative() {
        return !isSimulator() && "ios".equals(CN.getPlatformName());
    }

    /**
     * Returns true if the app is running as Javascript port
     *
     * @return
     */
    public static boolean isJavascript() {
        return !isSimulator() && "HTML5".equals(CN.getPlatformName());
    }
}

然后,在您的主类中,注释theme = UIManager.initFirstTheme("/theme");行,并将其替换为:

// theme = UIManager.initFirstTheme("/theme");
// We assume that CSS support is enabled
CSSUtilities.loadMultipleCSSes("theme");

就这些。这是用法示例:

Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("(Recognized) screen width: " + (hi.getWidth() / CN.convertToPixels(1)) + " mm"));
hi.add(new SpanLabel("This text enters a line on a 70mm screen. Do tests."));
hi.add(FontImage.createMaterial(FontImage.MATERIAL_LOCAL_RESTAURANT, "Label", CSSUtilities.getResized(10.0f)));
hi.show();

请注意,识别出的宽度不是实际宽度,可以不同:但是,我的代码可以确保即使在Codename One无法正确检测到宽度的情况下,文本也可以根据您的要求进行调整。

一些注意事项:

  • 此代码有限制,它要求垂直方向锁定,仅适用于智能手机屏幕(无平板电脑;

    ]
  • 请记住,Android和iOS的本机字体是不同的;

  • 此代码会自动调整您在CSS中指定的有关文本,边距和填充的尺寸(使用mm或pt,1pt约为0.35mm);

  • 对于其他所有内容,调整大小不是自动的,在示例代码中,我向您展示了如何自动调整图像;

  • 该代码被限制为将文本最多减少30%,在我的测试中,这很好,只要默认大小为70mm;

  • 该代码永远不会增加文本的大小:同样,我根据测试确定了这种行为,您可以根据需要进行操作。

  • 更准确地说,这段代码对我的帮助尤其是在那些无法正确报告其屏幕密度从而“愚蠢”代号为“ One。”的设备上。

我希望这对您有用。在真实设备上,它比在模拟器中更有用。

© www.soinside.com 2019 - 2024. All rights reserved.