Формула от px до dp, от dp до px android
Я пытаюсь вычислить переменное количество пикселей для плотности независимых пикселей и наоборот.
Эта формула (px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160));
не работает на небольших устройствах, потому что он делится на ноль.
Это моя формула dp to px:
px = (int)(dp * (displayMetrics.densityDpi / 160));
Может ли кто-нибудь дать мне несколько советов?
21 ответ
Примечание: широко используемое решение выше основано на displayMetrics.density
, Тем не менее, документы объясняют, что это значение является округленным значением, используемым с экраном "корзины". Например. на моем Nexus 10 он возвращает 2, где реальное значение будет 298dpi (реальное) / 160dpi (по умолчанию) = 1,8625.
В зависимости от ваших требований вам может потребоваться точное преобразование, которое может быть достигнуто следующим образом:
[Edit] Это не предназначено для смешивания с внутренним модулем dp Android, так как это, конечно, все еще основано на экранах. Используйте это там, где вам нужен блок, который должен отображать один и тот же реальный размер на разных устройствах.
Преобразовать дп в пиксель:
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
Преобразовать пиксель в дп:
public int pxToDp(int px) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
Обратите внимание, что есть свойства xdpi и ydpi, которые вы можете различать, но я не могу представить себе нормальное отображение, в котором эти значения сильно различаются.
Я решил свою проблему, используя следующие формулы. Пусть другие люди выиграют от этого.
dp to px:
displayMetrics = context.getResources().getDisplayMetrics();
return (int)((dp * displayMetrics.density) + 0.5);
px до dp:
displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((px/displayMetrics.density)+0.5);
Эффективный способ когда-либо
DP to Pixel:
private int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
Пиксель в DP:
private int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Надеюсь, что это поможет вам.
px до dp:
int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
.getDisplayMetrics());
Просто позвони getResources().getDimensionPixelSize(R.dimen.your_dimension)
конвертировать из dp
единицы к пикселям
Используйте эту функцию
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
Используйте эти расширения Kotlin:
/**
* Converts Pixel to DP.
*/
val Int.pxToDp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
/**
* Converts DP to Pixel.
*/
val Int.dpToPx: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
В большинстве случаев функции преобразования вызываются часто. Мы можем оптимизировать его, добавив памятку. Таким образом, он не вычисляет каждый раз, когда вызывается функция.
Давайте объявим HashMap, в котором будут храниться вычисленные значения.
private static Map<Float, Float> pxCache = new HashMap<>();
Функция, которая вычисляет значения пикселей:
public static float calculateDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return px;
}
Функция запоминания, которая возвращает значение из HashMap и поддерживает запись предыдущих значений.
Мемоизация может быть реализована различными способами в Java. Для Java 7:
public static float convertDpToPixel(float dp, final Context context) {
Float f = pxCache.get(dp);
if (f == null) {
synchronized (pxCache) {
f = calculateDpToPixel(dp, context);
pxCache.put(dp, f);
}
}
return f;
}
Java 8 поддерживает функцию Lambda:
public static float convertDpToPixel(float dp, final Context context) {
pxCache.computeIfAbsent(dp, y ->calculateDpToPixel(dp,context));
}
Благодарю.
Элегантное котлин-решение :)
val Int.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Float.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Int.px get() = this * Resources.getSystem().displayMetrics.density
val Float.px get() = this * Resources.getSystem().displayMetrics.density
Применение:
val dpValue = 2.dp
val pxFromDpValue = 2.px
Важно:
я не уверен, если
Resources.getSystem()
будет корректно работать с изменением ориентации.
Если вы хотите работать, например, с фрагментом или действием, просто добавьте его в базовый фрагмент или базовое действие и используйте его следующим образом:
abstract class BaseFragment : Fragment() {
val Int.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Float.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Int.px get() = this * resources.displayMetrics.density
val Float.px get() = this * resources.displayMetrics.density
.......
}
Ниже функции хорошо работали для меня на всех устройствах.
Это взято от https://gist.github.com/laaptu/7867851
public static float convertPixelsToDp(float px){
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return Math.round(dp);
}
public static float convertDpToPixel(float dp){
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
Попробуйте это http://labs.skinkers.com/content/android_dp_px_calculator/
// для получения в виде десятичной дроби
public static float convertPixelsToDp(float px, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return Math.round(dp);
}
public static float convertDpToPixel(float dp, Context context) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
// for getting in terms of Integer
private int convertPxToDp(int px, Context context) {
Resources resources = context.getResources();
return Math.round(px / (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
private int convertDpToPx(int dp, Context context) {
Resources resources = context.getResources();
return Math.round(dp * (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
________________________________________________________________________________
public static float convertPixelsToDp(float px){
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return Math.round(dp);
}
public static float convertDpToPixel(float dp){
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
private int convertDpToPx(int dp){
return Math.round(dp*(getResources().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));
}
private int convertPxToDp(int px){
return Math.round(px/(Resources.getSystem().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));
}
Если вам нужен онлайн-калькулятор для преобразования DP, SP, дюймов, миллиметров, точек или пикселей друг в друга с разной плотностью экрана, это наиболее полный из известных мне инструментов.
Ты можешь использовать [DisplayMatrics][1]
и определить плотность экрана. Что-то вроде этого:
int pixelsValue = 5; // margin in pixels
float d = context.getResources().getDisplayMetrics().density;
int margin = (int)(pixelsValue * d);
Насколько я помню, лучше использовать настил для смещений и округление по ширине.
DisplayMetrics displayMetrics = contaxt.getResources() .getDisplayMetrics();
int densityDpi = (int) (displayMetrics.density * 160f);
int ratio = (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
int px;
if (ratio == 0) {
px = dp;
} else {
px = Math.round(dp * ratio);
}
Ответ, принятый выше, не является полностью точным. Согласно информации, полученной при проверке исходного кода Android:
Resources.getDimension()
а также getDimensionPixelOffset()
/getDimensionPixelSize()
отличаются только тем, что прежние возвращения float
в то время как последние два возвращают одинаковое значение, округленное до int
appropriatelly. Для всех них возвращаемое значение в необработанных пикселях.
Все три функции реализуются путем вызова Resources.getValue()
и преобразование, полученное таким образом TypedValue
позвонив TypedValue.complexToDimension()
, TypedValue.complexToDimensionPixelOffset()
а также TypedValue.complexToDimensionPixelSize()
соответственно.
Поэтому, если вы хотите получить "сырое" значение вместе с единицей, указанной в источнике XML, вызовите Resources.getValue()
и использовать методы TypedValue
учебный класс.
Не стесняйтесь использовать этот метод, который я написал:
int dpToPx(int dp)
{
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
С помощью других ответов я написал эту функцию.
public static int convertToPixels(Context context, int nDP)
{
final float conversionScale = context.getResources().getDisplayMetrics().density;
return (int) ((nDP * conversionScale) + 0.5f) ;
}
Вариант ct_robs ответ выше, если вы используете целые числа, это не только позволяет избежать деления на 0, но и дает полезный результат на небольших устройствах:
в целочисленных вычислениях, включающих деление для наибольшей точности, сначала умножьте перед делением, чтобы уменьшить эффекты усечения.
px = dp * dpi / 160 dp = px * 160 / dpi
5 * 120 = 600/160 = 3
вместо
5 * (120 / 160 = 0) = 0
если вы хотите округленный результат, сделайте это
px = (10 * dp * dpi / 160 + 5) / 10 dp = (10 * px * 160 / dpi + 5) / 10
10 * 5 * 120 = 6000/160 = 37 + 5 = 42/10 = 4
Вот другой способ сделать это с помощью расширений kotlin:
val Int.dpToPx: Int
get() = Math.round(this * Resources.getSystem().displayMetrics.density)
val Int.pxToDp: Int
get() = Math.round(this / Resources.getSystem().displayMetrics.density)
и тогда его можно использовать как угодно из любого места
12.dpToPx
244.pxToDp