如何解析维度字符串并将其转换为维度值

时间:2011-12-01 15:37:01

标签: android android-layout

我正在寻找一种方法,将"30dp"之类的字符串动态转换为类似于像素数量的int。这意味着StaticClass.theMethodImSearchingFor("16px")将返回16 我的应用程序将动态获取这些字符串,我需要一种方法将其存储为像素值,以便以后使用 我已经查看了Android Source code,主要是类ResourcesTypedArrayTypedValue,但我找不到任何有用的内容。

4 个答案:

答案 0 :(得分:54)

如果您需要android资源维度作为int,您可以在代码中执行此操作:

context.getResources().getDimensionPixelSize(R.dimen.your_dimen_res);

答案 1 :(得分:13)

我自己需要这个,所以我写了一个类来处理它。此答案中的所有代码均在Apache License 2.0下获得许可。享受。

有两种静态方法可以模仿两种TypedValue方法。 DimensionConverter.stringToDimension()模仿TypedValue.complexToDimension。 DimensionConverter.stringToDimensionPixelSize()模仿TypedValue.complexToDimensionPixelSize

支持所有当前单位。接受维度字符串,如“33sp”,“44 dp”,并为不良格式抛出异常。

简单易用:

String dimension = "38dp";
Log.i(TAG, "Testing: " + dimension);
try {
    Log.i(TAG, "Converts to: " + DimensionConverter.stringToDimension(dimension, resources.getDisplayMetrics()));
} catch (NumberFormatException exception) {
    Log.i(TAG, "Unable to convert.");
}

这里的课程:

public class DimensionConverter {

    // -- Initialize dimension string to constant lookup.
    public static final Map<String, Integer> dimensionConstantLookup = initDimensionConstantLookup();
    private static Map<String, Integer> initDimensionConstantLookup() {
        Map<String, Integer> m = new HashMap<String, Integer>();  
        m.put("px", TypedValue.COMPLEX_UNIT_PX);
        m.put("dip", TypedValue.COMPLEX_UNIT_DIP);
        m.put("dp", TypedValue.COMPLEX_UNIT_DIP);
        m.put("sp", TypedValue.COMPLEX_UNIT_SP);
        m.put("pt", TypedValue.COMPLEX_UNIT_PT);
        m.put("in", TypedValue.COMPLEX_UNIT_IN);
        m.put("mm", TypedValue.COMPLEX_UNIT_MM);
        return Collections.unmodifiableMap(m);  
    }
    // -- Initialize pattern for dimension string.
    private static final Pattern DIMENSION_PATTERN = Pattern.compile("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");

    public static int stringToDimensionPixelSize(String dimension, DisplayMetrics metrics) {
        // -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics).
        InternalDimension internalDimension = stringToInternalDimension(dimension);
        final float value = internalDimension.value;
        final float f = TypedValue.applyDimension(internalDimension.unit, value, metrics);
        final int res = (int)(f+0.5f);
        if (res != 0) return res;
        if (value == 0) return 0;
        if (value > 0) return 1;
        return -1;
    }

    public static float stringToDimension(String dimension, DisplayMetrics metrics) {
        // -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics).
        InternalDimension internalDimension = stringToInternalDimension(dimension);
        return TypedValue.applyDimension(internalDimension.unit, internalDimension.value, metrics);
    }

    private static InternalDimension stringToInternalDimension(String dimension) {
        // -- Match target against pattern.
        Matcher matcher = DIMENSION_PATTERN.matcher(dimension);
        if (matcher.matches()) {
            // -- Match found.
            // -- Extract value.
            float value = Float.valueOf(matcher.group(1)).floatValue();
            // -- Extract dimension units.
            String unit = matcher.group(3).toLowerCase();
            // -- Get Android dimension constant.
            Integer dimensionUnit = dimensionConstantLookup.get(unit);
            if (dimensionUnit == null) {
                // -- Invalid format.
                throw new NumberFormatException();
            } else {
                // -- Return valid dimension.
                return new InternalDimension(value, dimensionUnit);
            }
        } else {
            // -- Invalid format.
            throw new NumberFormatException();
        }        
    }

    private static class InternalDimension {
        float value;
        int unit;

        public InternalDimension(float value, int unit) {
            this.value = value;
            this.unit = unit;
        }
    }
}

答案 2 :(得分:1)

感谢mindriot,工作得很好并且是救星。

这是在C#

注意:如果出于某种原因你不能使用Integer类型(vs int)(它将是Mono中的Java Integers),我在所有关联的注释中都留下了使用C#int的代码。只需在您看到的地方交换未注释的Integer代码的注释int代码。

必须使用Integer,以便在检查后缀的Dictionary / Map(TryGetValue)时可以确定是否没有匹配(在这种情况下它将为null;如果使用int,则out param将是0,它对应于地图的第一个条目,显然不起作用。太糟糕了,TryGetValue在没有匹配时没有返回一个negeative值!?)。

public class DimensionConverter
{
    // -- Initialize dimension string to constant lookup.     

    //public static readonly Dictionary<string, int> dimensionConstantLookup = initDimensionConstantLookup();
    public static readonly Dictionary<string, Integer> dimensionConstantLookup = initDimensionConstantLookup();

    //private static Dictionary<string, int> initDimensionConstantLookup()
    private static Dictionary<string, Integer> initDimensionConstantLookup()
    {
        //Dictionary<string, int> m = new Dictionary<string, int>();
        Dictionary<string, Integer> m = new Dictionary<string, Integer>();

        m.Add("px", (Integer)((int)ComplexUnitType.Px));
        m.Add("dip", (Integer)((int)ComplexUnitType.Dip));
        m.Add("dp", (Integer)((int)ComplexUnitType.Dip));
        m.Add("sp", (Integer)((int)ComplexUnitType.Sp));
        m.Add("pt", (Integer)((int)ComplexUnitType.Pt));
        m.Add("in", (Integer)((int)ComplexUnitType.In));
        m.Add("mm", (Integer)((int)ComplexUnitType.Mm));

        /*m.Add("px", (int)ComplexUnitType.Px);
        m.Add("dip", (int)ComplexUnitType.Dip);
        m.Add("dp", (int)ComplexUnitType.Dip);
        m.Add("sp", (int)ComplexUnitType.Sp);
        m.Add("pt", (int)ComplexUnitType.Pt);
        m.Add("in", (int)ComplexUnitType.In);
        m.Add("mm", (int)ComplexUnitType.Mm);*/

        return m;
    }

    // -- Initialize pattern for dimension string.     

    private static Regex DIMENSION_PATTERN = new Regex("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");

    public static int stringToDimensionPixelSize(string dimension, DisplayMetrics metrics)
    {
        // -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics).         

        InternalDimension internalDimension = stringToInternalDimension(dimension);

        float value = internalDimension.value;
        //float f = TypedValue.ApplyDimension((ComplexUnitType)internalDimension.unit, value, metrics);
        float f = TypedValue.ApplyDimension((ComplexUnitType)(int)internalDimension.unit, value, metrics);
        int res = (int)(f + 0.5f);

        if (res != 0) return res;
        if (value == 0) return 0;
        if (value > 0) return 1;

        return -1;
    }

    public static float stringToDimension(String dimension, DisplayMetrics metrics)
    {
        // -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics).         

        InternalDimension internalDimension = stringToInternalDimension(dimension);

        //return TypedValue.ApplyDimension((ComplexUnitType)internalDimension.unit, internalDimension.value, metrics);
        return TypedValue.ApplyDimension((ComplexUnitType)(int)internalDimension.unit, internalDimension.value, metrics);
    }

    private static InternalDimension stringToInternalDimension(String dimension)
    {
        // -- Match target against pattern.         

        MatchCollection matches = DIMENSION_PATTERN.Matches(dimension);

        if (matches.Count > 0)
        {
            Match matcher = matches[0];

            // -- Match found.             
            // -- Extract value.             
            float value = Float.ValueOf(matcher.Groups[1].Value).FloatValue();

            // -- Extract dimension units.             
            string unit = matcher.Groups[3].ToString().ToLower();

            // -- Get Android dimension constant.             
            //int dimensionUnit;

            Integer dimensionUnit;
            dimensionConstantLookup.TryGetValue(unit, out dimensionUnit);

            //if (dimensionUnit == ????)
            if (dimensionUnit == null)
            {
                // -- Invalid format.                 
                throw new NumberFormatException();
            }
            else
            {
                // -- Return valid dimension.                 
                return new InternalDimension(value, dimensionUnit);
            }
        }
        else
        {
            // -- Invalid format.             
            throw new NumberFormatException();
        }
    }

    private class InternalDimension
    {
        public float value;
        //public int unit;
        public Integer unit;

        //public InternalDimension(float value, int unit)
        public InternalDimension(float value, Integer unit)
        {
            this.value = value;
            this.unit = unit;
        }
    }
}

答案 3 :(得分:0)

link可能会帮助您找出转换效果,但由于像素和与密度无关的像素不是1:1的匹配,因此会出现一些(次要的)失真。

  

这些单位(dp)相对于160 dpi的屏幕,因此一个dp是一个   160 dpi屏幕上的像素。 dp与像素的比率将随之变化   屏幕密度,但不一定是正比例。