Преобразование пикселей в дп
Я создал свое приложение с высотой и шириной в пикселях для устройства Pantech с разрешением 480x800.
Мне нужно конвертировать высоту и ширину для устройства G1. Я думал, что преобразование его в dp решит проблему и обеспечит одинаковое решение для обоих устройств.
Есть ли простой способ конвертировать пиксели в dp? Какие-либо предложения?
36 ответов
// 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){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
return px;
}
/**
* 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
наldpi
(120
точек на дюйм)1.0
наmdpi
(160
точек на дюйм; базовый уровень)1.5
наhdpi
(240
точек на дюйм)2.0
наxhdpi
(320
точек на дюйм)3.0
наxxhdpi
(480
точек на дюйм)4.0
наxxxhdpi
(640
точек на дюйм)
Используйте этот онлайн-конвертер, чтобы поиграться со значениями точек на дюйм.
РЕДАКТИРОВАТЬ: Кажется, нет никакого отношения 1:1 между dpi
ведро и density
, Похоже, Nexus 5X
являющийся xxhdpi
имеет density
ценность 2.625
(вместо 3
). Убедитесь сами в метриках устройства.
Вы можете использовать это.. без контекста
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, использование этого подхода может вызвать проблемы, если система изменит плотность. Так что знайте об этом!
Лично я использую контекст, чтобы сделать это.
Если вы можете использовать измерения 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);
Согласно Руководству по разработке Android:
px = dp * (dpi / 160)
Но часто вам захочется сделать это наоборот, когда вы получите дизайн, который указан в пикселях. Так:
dp = px / (dpi / 160)
Если вы используете устройство с разрешением 240 точек на дюйм, это соотношение равно 1,5 (как указано выше), поэтому это означает, что значок 60px в приложении равен 40dp.
Без 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);
}
Использование 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()
ЗаDP to Pixel
Создать значение в dimens.xml
<dimen name="textSize">20dp</dimen>
Получить это значение в pixel
как:
int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);
Для тех, кто использует 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
Поэтому вы можете использовать следующий составитель для вычисления правильного количества пикселей по измерению, указанному в dp
public int convertToPx(int dp) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
В Android SDK есть утилита по умолчанию: http://developer.android.com/reference/android/util/TypedValue.html
float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Котлин
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);
}
Это должно дать вам преобразование дп в пиксели:
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);
}
Вероятно, лучший способ, если у вас есть измерение внутри values / измерение, это получить измерение непосредственно из метода getDimension(), он вернет вам измерение, уже преобразованное в значение в пикселях.
context.getResources().getDimension(R.dimen.my_dimension)
Просто чтобы лучше объяснить это,
getDimension(int resourceId)
вернет размер, уже преобразованный в пиксель как плавающий элемент.
getDimensionPixelSize(int resourceId)
вернет то же самое, но усеченное до int, так что как INTEGER.
public static int dp2px(Resources resource, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,resource.getDisplayMetrics());
}
Чтобы преобразовать пиксель в дп. public static float px2dp(Resources resource, float px) {
return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}
где ресурс это context.getResources().
Котлин
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;
}
Как это:
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;
}
}
зависит от контекста, возвращаемого значения с плавающей запятой, статического метода
Более элегантный подход с использованием функции расширения 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}")
Чтобы конвертировать пиксели в dp, используйте 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);
Если вы разрабатываете приложение, критичное к производительности, рассмотрите следующий оптимизированный класс:
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;
}
}
Много отличных решений выше. Однако лучшее решение, которое я нашел, это дизайн Google:
Вот как это работает для меня:
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int h = displaymetrics.heightPixels;
float d = displaymetrics.density;
int heightInPixels=(int) (h/d);
Вы можете сделать то же самое для ширины.
Вы должны использовать dp так же, как и пиксели. Это все, что они есть; отображать независимые пиксели. Используйте те же числа, что и на экране средней плотности, и размер будет магически правильным на экране высокой плотности.
Однако, похоже, вам нужна опция fill_parent в вашем макете. Используйте fill_parent, когда вы хотите, чтобы ваше представление или элемент управления расширились до всех оставшихся размеров в родительском контейнере.
private fun toDP(context: Context,value: Int): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
value.toFloat(),context.resources.displayMetrics).toInt()
}
PX
а также DP
разные, но похожие.
DP
разрешение, когда вы учитываете только физический размер экрана. Когда вы используете DP
он будет масштабировать ваш макет на другие похожие по размеру экраны с pixel
плотности.
Иногда вы действительно хотите pixels
хотя, и когда вы имеете дело с измерениями в коде, вы всегда имеете дело с реальным pixels
, если вы не конвертируете их.
Так что на андроид устройстве нормального размера hdpi
экран, 800x480 is 533x320
в DP
(Я верю). Преобразовать DP
в pixels /1.5
, чтобы конвертировать обратно *1.5
, Это только для одного размера экрана и dpi
, это будет меняться в зависимости от дизайна. Наши художники дают мне pixels
хотя и я преобразую в DP
с вышеупомянутым 1.5
уравнение.
Если вы хотите целочисленные значения, то использование Math.round() округляет число с плавающей точкой до ближайшего целого числа.
public static int pxFromDp(final float dp) {
return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
}
Лучший ответ приходит от самого фреймворка Android: просто используйте это равенство...
public static int dpToPixels(final DisplayMetrics display_metrics, final float dps) {
final float scale = display_metrics.density;
return (int) (dps * scale + 0.5f);
}
(конвертирует dp в px)