Skip to content Skip to sidebar Skip to footer

How To Parse A Dimension String And Convert It To A Dimension Value

I'm looking for a way to dynamically convert a String like '30dp' into an int that resembles the amount of pixels. This would mean that StaticClass.theMethodImSearchingFor('16px')

Solution 1:

If you need the android resource dimen as a int you can do this in your code:

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

Solution 2:

I needed this myself so I wrote a class to handle it. All code in this answer is licensed under Apache License 2.0. Enjoy.

There are two static methods that mimic two TypedValue methods. DimensionConverter.stringToDimension() mimics TypedValue.complexToDimension. DimensionConverter.stringToDimensionPixelSize() mimics TypedValue.complexToDimensionPixelSize.

Supports all current units. Will accept dimension strings like "33sp", " 44 dp " and throw an exception for bad formats.

Simple to use:

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.");
}

Class here:

publicclassDimensionConverter {

    // -- Initialize dimension string to constant lookup.publicstaticfinal Map<String, Integer> dimensionConstantLookup = initDimensionConstantLookup();
    privatestatic Map<String, Integer> initDimensionConstantLookup() {
        Map<String, Integer> m = newHashMap<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.privatestaticfinalPatternDIMENSION_PATTERN= Pattern.compile("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");

    publicstaticintstringToDimensionPixelSize(String dimension, DisplayMetrics metrics) {
        // -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics).InternalDimensioninternalDimension= stringToInternalDimension(dimension);
        finalfloatvalue= internalDimension.value;
        finalfloatf= TypedValue.applyDimension(internalDimension.unit, value, metrics);
        finalintres= (int)(f+0.5f);
        if (res != 0) return res;
        if (value == 0) return0;
        if (value > 0) return1;
        return -1;
    }

    publicstaticfloatstringToDimension(String dimension, DisplayMetrics metrics) {
        // -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics).InternalDimensioninternalDimension= stringToInternalDimension(dimension);
        return TypedValue.applyDimension(internalDimension.unit, internalDimension.value, metrics);
    }

    privatestatic InternalDimension stringToInternalDimension(String dimension) {
        // -- Match target against pattern.Matchermatcher= DIMENSION_PATTERN.matcher(dimension);
        if (matcher.matches()) {
            // -- Match found.// -- Extract value.floatvalue= Float.valueOf(matcher.group(1)).floatValue();
            // -- Extract dimension units.Stringunit= matcher.group(3).toLowerCase();
            // -- Get Android dimension constant.IntegerdimensionUnit= dimensionConstantLookup.get(unit);
            if (dimensionUnit == null) {
                // -- Invalid format.thrownewNumberFormatException();
            } else {
                // -- Return valid dimension.returnnewInternalDimension(value, dimensionUnit);
            }
        } else {
            // -- Invalid format.thrownewNumberFormatException();
        }        
    }

    privatestaticclassInternalDimension {
        float value;
        int unit;

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

Solution 3:

Thanks to mindriot, works great and is a lifesaver.

Here it is in C#

note: If for some reason you cannot use Integer types (vs int's) (which will be Java Integers in Mono), I left the code that uses C# int's in comments everywhere that is associated. Just swap the commented int code for the uncommented Integer code everywhere you see it.

Had to use Integer so that it can be determined if there is no match when checking the Dictionary/Map (TryGetValue) of suffixs (in which case it'll be null; if ints are used instead, then the out param will be 0, which corresponds to the first entry of the map, which obviously doesn't work. Too bad TryGetValue didn't return a negeative value upon no match!?).

publicclassDimensionConverter
{
    // -- Initialize dimension string to constant lookup.     //public static readonly Dictionary<string, int> dimensionConstantLookup = initDimensionConstantLookup();publicstaticreadonly Dictionary<string, Integer> dimensionConstantLookup = initDimensionConstantLookup();

    //private static Dictionary<string, int> initDimensionConstantLookup()privatestatic 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.     privatestatic Regex DIMENSION_PATTERN = new Regex("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");

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

        InternalDimension internalDimension = stringToInternalDimension(dimension);

        floatvalue = 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) return0;
        if (value > 0) return1;

        return-1;
    }

    publicstaticfloatstringToDimension(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);
    }

    privatestatic 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.             floatvalue = 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.                 thrownew NumberFormatException();
            }
            else
            {
                // -- Return valid dimension.                 returnnew InternalDimension(value, dimensionUnit);
            }
        }
        else
        {
            // -- Invalid format.             thrownew NumberFormatException();
        }
    }

    privateclassInternalDimension
    {
        publicfloatvalue;
        //public int unit;public Integer unit;

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

Solution 4:

This link might help you figure out your conversion, however since pixels and density-independent pixels are not a 1:1 matchup, expect some (minor) distortions.

These units (dp) are relative to a 160 dpi screen, so one dp is one pixel on a 160 dpi screen. The ratio of dp-to-pixel will change with the screen density, but not necessarily in direct proportion.

Post a Comment for "How To Parse A Dimension String And Convert It To A Dimension Value"