Как проанализировать строку измерения и преобразовать ее в значение измерения - PullRequest
19 голосов
/ 01 декабря 2011

Я ищу способ динамического преобразования строки типа "30dp" в целое число, похожее на количество пикселей.Это будет означать, что StaticClass.theMethodImSearchingFor("16px") вернет 16.
Мое приложение получит эти строки динамически, и мне нужен способ сохранить его как значение в пикселях для использования позже.
Я уже посмотрел на Исходный код Android , в основном классы Resources, TypedArray и TypedValue, но я не смог найти ничего полезного.

Ответы [ 4 ]

55 голосов
/ 01 декабря 2011

Если вам нужен размер ресурса Android как int, вы можете сделать это в своем коде:

context.getResources().getDimensionPixelSize(R.dimen.your_dimen_res);
13 голосов
/ 06 июля 2012

Мне это нужно было самому, поэтому я написал класс, чтобы справиться с этим.Весь код в этом ответе распространяется под 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;
        }
    }
}
1 голос
/ 03 октября 2012

Благодаря mindriot, прекрасно работает и спасает жизнь.

Здесь это в C #

note : если по какой-то причине вы не можете использовать целочисленные типы (противint's) (которые будут Java Integer в Mono), я оставил код, который использует C # int, в комментариях везде, где это связано.Просто поменяйте местами закомментированный int-код для некомментированного целочисленного кода везде, где вы его видите.

Пришлось использовать Integer, чтобы можно было определить, нет ли совпадения при проверке словаря / карты (TryGetValue) суффиксов (вв этом случае он будет нулевым, если вместо него используются целые, то выходной параметр будет равен 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;
        }
    }
}
0 голосов
/ 01 декабря 2011

Эта ссылка может помочь вам выяснить конверсию, однако, поскольку пиксели и пиксели, не зависящие от плотности, не соответствуют 1: 1, ожидайте некоторые (незначительные) искажения.

Эти единицы измерения (dp) относятся к экрану с разрешением 160 точек на дюйм, поэтому один dp равен одному пикселю на экране с разрешением 160 точек на дюйм.Соотношение dp-to-pixel будет меняться в зависимости от плотности экрана, но не обязательно в прямой пропорции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...