"30dp"
这样的字符串动态地转换为类似于像素数量的整数。这意味着StaticClass.theMethodImSearchingFor("16px")
会返回16
。我的应用程序会动态获取这些字符串,并且需要一种将其存储为像素值以便以后使用的方法。
我已经查看了Android源代码,主要是
Resources
、TypedArray
和TypedValue
类,但我找不到有用的东西。"30dp"
这样的字符串动态地转换为类似于像素数量的整数。这意味着StaticClass.theMethodImSearchingFor("16px")
会返回16
。Resources
、TypedArray
和TypedValue
类,但我找不到有用的东西。如果你需要将 Android 资源 dimen 转换为 int 类型,你可以在代码中这样做:
context.getResources().getDimensionPixelSize(R.dimen.your_dimen_res);
我自己需要这个功能,所以我编写了一个处理它的类。此答案中的所有代码都是根据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;
}
}
}
感谢mindriot,它非常好用,是一个救命稻草。
这是C#版本的代码:
注意:如果由于某些原因您无法使用整数类型(而不是int),则在与之相关的所有地方,我都将使用C# int的代码注释掉。只需将注释的int代码替换为您看到的未注释的Integer代码即可。
必须使用Integer,以便在检查后缀的Dictionary/Map(TryGetValue)时确定是否没有匹配项(在这种情况下,它将为null;如果使用int,则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;
}
}
}
这个链接可能会帮助你解决转换问题,但由于像素和密度无关像素不是一对一的匹配,所以可能会出现一些(轻微)的扭曲。
这些单位(dp)是相对于160 dpi屏幕的,因此在160 dpi屏幕上,一个dp就是一个像素。 dp到像素的比率将随着屏幕密度而改变,但不一定成正比例。