如何parsing维度string并将其转换为维度值

我正在寻找一种方法来dynamic地将像"30dp"这样的string转换为类似像素数量的int值。 这意味着StaticClass.theMethodImSearchingFor("16px")将返回16
我的应用程序将dynamic获得这些string,我需要一种方式来存储它作为一个像素值,以便以后使用。
我已经看了Android的源代码 ,主要是类ResourcesTypedArrayTypedValue ,但我找不到任何有用的东西。

Solutions Collecting From Web of "如何parsing维度string并将其转换为维度值"

如果你需要android资源维度作为int你可以在你的代码中做到这一点:

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

我自己需要这个,所以我写了一个类来处理它。 这个答案中的所有代码都是在Apache许可证2.0下授权的 。 请享用。

有两个模仿两个TypedValue方法的静态方法。 DimensionConverter.stringToDimension()模仿TypedValue.complexToDimension 。 DimensionConverter.stringToDimensionPixelSize()模仿TypedValue.complexToDimensionPixelSize 。

支持所有当前单位。 将接受像“33sp”,“44 dp”这样的维度string,并为不良格式引发exception。

简单易用:

 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; } } } 

感谢mindriot,伟大的工作,是一个救星。

这里是在C#

注意 :如果由于某种原因,你不能使用Integertypes(vs int)(这将是Mono中的Java Integers),所以我留下了在所有关联的注释中使用C#int的代码。 只要将注释的int代码换成您看到它的任何地方的未注释的Integer代码即可。

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

 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; } } } 

这个链接可能会帮助你找出你的转换,但是由于像素和密度无关的像素不是1:1的匹配,所以会期望一些(小的)失真。

这些单位(DP)是相对于一个160 dpi的屏幕,所以一个DP是160 dpi屏幕上的一个像素。 dp与像素的比率将随着屏幕密度而改变,但不一定成正比。