Ответ 1
// Converts 14 dip into its equivalent px
float dip = 14f;
Resources r = getResources();
float px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip,
r.getDisplayMetrics()
);
Я создал свое приложение с высотой и шириной, заданной в пикселях для устройства Pantech с разрешением 480x800.
Мне нужно преобразовать высоту и ширину для устройства G1. Я думал, что преобразование его в dp решит проблему и обеспечит такое же решение для обоих устройств.
Есть ли простой способ конвертировать пиксели в dp? Любые предложения?
// Converts 14 dip into its equivalent px
float dip = 14f;
Resources r = getResources();
float px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip,
r.getDisplayMetrics()
);
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
public static float convertDpToPixel(float dp, Context context){
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
/**
* This method converts device specific pixels to density independent pixels.
*
* @param px A value in px (pixels) unit. Which we need to convert into db
* @param context Context to get resources and device specific display metrics
* @return A float value to represent dp equivalent to px value
*/
public static float convertPixelsToDp(float px, Context context){
return px / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
Желательно добавить класс Util.java
public static float dpFromPx(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float pxFromDp(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;
density
равно
.75
on ldpi
(120
dpi)1.0
on mdpi
(160
dpi, базовая линия)1.5
on hdpi
(240
dpi)2.0
on xhdpi
(320
dpi)3.0
on xxhdpi
(480
dpi)4.0
on xxxhdpi
(640
dpi)Используйте этот онлайн-конвертер, чтобы играть со значениями dpi.
EDIT:
Кажется, нет отношения 1:1 между ведром dpi
и density
. Похоже, что Nexus 5X
имеет xxhdpi
имеет значение density
2.625
(вместо 3
). Посмотрите сами в Показатели устройства.
Если вы можете использовать размеры XML, это очень просто!
В res/values/dimens.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="thumbnail_height">120dp</dimen>
...
...
</resources>
Затем в вашей Java:
getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Вы можете использовать это.. без контекста
public static int pxToDp(int px) {
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
Как упомянул @Stan.. использование этого подхода может вызвать проблемы, если система изменит плотность. Так что знайте об этом!
Лично я использую контекст, чтобы сделать это. Это просто еще один подход, которым я хотел бы поделиться с вами
Согласно Руководству по разработке Android:
px = dp * (dpi / 160)
Но часто вам нужно делать это наоборот, когда вы получаете дизайн, который указан в пикселях. Итак:
dp = px / (dpi / 160)
Если вы используете устройство с разрешением 240 точек на дюйм, это соотношение равно 1,5 (как указано выше), поэтому это означает, что значок 60 пикселей равен 40 дп в приложении.
Без Context
, изящные статические методы:
public static int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
public static int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Для DP to Pixel
Создайте значение в dimens.xml
<dimen name="textSize">20dp</dimen>
Получите это значение в pixel
как:
int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);
Поэтому вы можете использовать следующий формулятор для вычисления правильного количества пикселей из измерения, указанного в dp
public int convertToPx(int dp) {
// Get the screen density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
Для тех, кто использует Kotlin:
val Int.toPx: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.toDp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
Использование:
64.toPx
32.toDp
В SDK для Android используется по умолчанию: http://developer.android.com/reference/android/util/TypedValue.html
float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
использование kotlin-extension делает его лучше
fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()
fun Int.toDp(context: Context): Int = (this / context.resources.displayMetrics.density).toInt()
ОБНОВИТЬ:
Поскольку displayMetrics
является частью глобальных общих ресурсов, мы можем использовать Resources.getSystem()
fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
Это должно дать вам преобразование дп в пиксели:
public static int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
Это должно дать вам преобразование пикселей в dp:
public static int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
fun convertDpToPixel(dp: Float, context: Context): Float {
return dp * (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
public static float convertDpToPixel(float dp, Context context) {
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
public static float convertPixelsToDp(float px, Context context) {
return px / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
Вероятно, лучший способ, если у вас есть измерение внутри значений /dimen, - это получить измерение непосредственно из метода getDimension(), оно вернет вам измерение, уже преобразованное в значение пикселя.
context.getResources().getDimension(R.dimen.my_dimension)
Чтобы лучше объяснить это,
getDimension(int resourceId)
вернет измерение, уже преобразованное в пиксель AS FLOAT.
getDimensionPixelSize(int resourceId)
вернет то же самое, но обрезается до int, поэтому AS AN INTEGER.
Смотрите ссылка на Android
public static int dp2px(Resources resource, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,resource.getDisplayMetrics());
}
Чтобы преобразовать пиксель в dp.
public static float px2dp(Resources resource, float px) {
return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}
где ресурсом является context.getResources().
вот так:
public class ScreenUtils {
public static float dpToPx(Context context, float dp) {
if (context == null) {
return -1;
}
return dp * context.getResources().getDisplayMetrics().density;
}
public static float pxToDp(Context context, float px) {
if (context == null) {
return -1;
}
return px / context.getResources().getDisplayMetrics().density;
}
}
в зависимости от контекста, возвращаемого значения float, статического метода
Более элегантный подход с использованием функции расширения kotlin
/**
* Converts dp to pixel
*/
val Int.dpToPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
/**
* Converts pixel to dp
*/
val Int.pxToDp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()
Использование:
println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
Если вы разрабатываете критичное для производительности приложение, рассмотрите следующий оптимизированный класс:
public final class DimensionUtils {
private static boolean isInitialised = false;
private static float pixelsPerOneDp;
// Suppress default constructor for noninstantiability.
private DimensionUtils() {
throw new AssertionError();
}
private static void initialise(View view) {
pixelsPerOneDp = view.getResources().getDisplayMetrics().densityDpi / 160f;
isInitialised = true;
}
public static float pxToDp(View view, float px) {
if (!isInitialised) {
initialise(view);
}
return px / pixelsPerOneDp;
}
public static float dpToPx(View view, float dp) {
if (!isInitialised) {
initialise(view);
}
return dp * pixelsPerOneDp;
}
}
Вот как это работает для меня:
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int h = displaymetrics.heightPixels;
float d = displaymetrics.density;
int heightInPixels=(int) (h/d);
Вы можете сделать то же самое для ширины.
чтобы конвертировать пиксели в дп используйте TypedValue.
Как указано в документации: Контейнер для динамически типизированного значения данных.
и используйте метод applyDimension:
public static float applyDimension (int unit, float value, DisplayMetrics metrics)
который преобразует распакованное комплексное значение данных, содержащее измерение, в его окончательное значение с плавающей запятой, как показано ниже:
Resources resource = getResources();
float dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 69, resource.getDisplayMetrics());
Надеюсь, это поможет.
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Вы должны использовать dp так же, как и пиксели. Это все, что они есть; отображать независимые пиксели. Используйте те же номера, что и на экране со средней плотностью, и размер будет волшебным образом на экране с высокой плотностью.
Однако, похоже, что вам нужен параметр fill_parent в вашем дизайне макета. Используйте fill_parent, когда вы хотите, чтобы ваш просмотр или элемент управления расширялся до всего оставшегося размера в родительском контейнере.
Много хороших решений выше. Тем не менее, лучшее решение, которое я нашел, это Google Design:
PX
и DP
являются разными, но похожими.
DP
- это разрешение, когда вы определяете только физический размер экрана. Когда вы используете DP
, он масштабирует ваш макет на другие экраны аналогичного размера с различными значениями плотности pixel
.
Иногда вы действительно хотите pixels
, хотя, когда вы имеете дело с измерениями в коде, вы всегда имеете дело с реальным pixels
, если вы не конвертируете их.
Итак, на устройстве Android, нормальном размере hdpi
, 800x480 is 533x320
в DP
(я считаю). Чтобы преобразовать DP
в pixels /1.5
, чтобы преобразовать обратно *1.5
. Это только для одного размера экрана и dpi
, это изменится в зависимости от дизайна. Наши художники дают мне pixels
, хотя и я обращаюсь к DP
с вышеупомянутым уравнением 1.5
.
Эта работа для меня (С#):
int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Если вы хотите целочисленные значения, то использование Math.round() округляет число с плавающей точкой до ближайшего целого числа.
public static int pxFromDp(final float dp) {
return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
}
Котлин
fun spToPx(ctx: Context, sp: Float): Float {
return sp * ctx.resources.displayMetrics.scaledDensity
}
fun pxToDp(context: Context, px: Float): Float {
return px / context.resources.displayMetrics.density
}
fun dpToPx(context: Context, dp: Float): Float {
return dp * context.resources.displayMetrics.density
}
Джава
public static float spToPx(Context ctx,float sp){
return sp * ctx.getResources().getDisplayMetrics().scaledDensity;
}
public static float pxToDp(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float dpToPx(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
Для Xamarin.Android
float DpToPixel(float dp)
{
var resources = Context.Resources;
var metrics = resources.DisplayMetrics;
return dp * ((float)metrics.DensityDpi / (int)DisplayMetricsDensity.Default);
}
Делать это нестатичным необходимо, когда вы делаете пользовательский рендер