Comments (24)
I wrote this utility:
fun Context.toPixelFromDip(value: Float) = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, resources.displayMetrics)
fun View.toPixelFromDip(value: Float) = context.toPixelFromDip(value)
Pro:
toPixelFromDip()
is very clear the origin and the destination- It's handy when you call this method from a
Context
or (more common) aView
, ex:View().apply { translationX = toPixelFromDip(2) }
from android-ktx.
I am not sure if it should be treated/interpreted as a conversion. mostly you simply want do pass a value in dp to a method which takes pixels. so 9.toDp()
I would assume converting 9px
to Ndp
but what we want is to be get the value 9
get treated as dp
and therefore I would prefer 9.asDp()
from android-ktx.
I think we would call these toDp
as conversion factory extensions are prefixed with "to".
from android-ktx.
Ah, that's fine, updating the description to to
. 👍
from android-ktx.
Just curious, why is it applied on Int & Float instead of on DisplayMetrics ike displayMetrics.toDp(9)
?
That way you can also name the param "pixel" so it's less confusing.
from android-ktx.
DisplayMetrics
is merely a tool needed to execute the conversion, the parameter that matters is the value. In an ideal world it would be 9.toDp()
.
from android-ktx.
Wouldn't accessing system Resources
just be sufficiet? So we can have something like:
val Int.dp: Int // or just return Float here
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
and use it in place like val side = 42.dp
?
from android-ktx.
I don't think so. Your application resources may have a different density. Maybe not now, but you don't know in future.
Also seems correct take it from application context.
from android-ktx.
What about using Number
?
fun Number.toDp(context: Context): Float {
if (this == 0) return 0f
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
context.resources.displayMetrics
)
}
from android-ktx.
This wouldn't work with multiple displays (virtual or physical).
from android-ktx.
In my opinion, this is the best implementation.
fun Number.dpToPx(): Int = (toFloat() * Resources.getSystem().displayMetrics.density + .5f).toInt()
from android-ktx.
@johanneslaubermoovel This doesn't work with negative numbers. Also you are relying on display metrics that might not match the display.
from android-ktx.
I am against using Number
as input since only Int
and Float
are the common types representing dimensions in Android.
This wouldn't work with multiple displays (virtual or physical).
@romainguy this just blew my mind. Say a secondary display is connected, which DisplayMetrics
then would the Resources
refers to?
from android-ktx.
Resources
will use the DisplayMetrics
of the Display
the Resources
came from.
from android-ktx.
I personally would go with the following methods:
fun Number.toDp(displayMetrics: DisplayMetrics? = null): Float = this.toFloat() / ((displayMetrics ?: Resources.getSystem().displayMetrics).densityDpi / 160f)
fun Number.toPx(displayMetrics: DisplayMetrics? = null) : Float = this.toFloat() * ((displayMetrics ?: Resources.getSystem().displayMetrics).densityDpi / 160f)
displayMetrics
is an optional parameter in case you have multiple displays. If not, you have the option of a simple 8.px()
or 12.px()
.
from android-ktx.
This seems error prone. The DisplayMetrics should be mandatory. BTW no need to / 160.0f, just use DisplayMetrics.density
instead (and you need to properly round and handle negative values correctly).
from android-ktx.
@JakeWharton What about using these converters?
fun Number.toDp(displayMetrics: DisplayMetrics): Float = this.toFloat() / displayMetrics.density
fun Number.toSp(displayMetrics: DisplayMetrics): Float = this.toFloat() / displayMetrics.scaledDensity
fun Number.toPx(displayMetrics: DisplayMetrics, fromSp: Boolean = false): Float
= this.toFloat() * (if (fromSp) displayMetrics.scaledDensity else displayMetrics.density)
from android-ktx.
These are incorrect, toPx
in particular does not round properly (which needs to take negative numbers into account). I would also prefer to not have a fromSp
boolean, but a separate method.
from android-ktx.
If you allow arch components, then you can have an onCreateProperty (which is like an Android-specific lateinit var
) and define extensions on Activity
and Fragment
:
/**
* Initializes a property with the DP value
* @receiver An [Activity] that is a [LifecycleOwner]
* @return [Float] representation of the DP value
* @see [onCreate]
*/
fun <T> T.dp(value: Float) where T : Activity, T : LifecycleOwner = onCreate {
value.toDp(resources.displayMetrics)
}
/**
* Initializes a property with the DP value
* @receiver A [Fragment] that is a [LifecycleOwner]
* @return [Int] representation of the DP value
* @see [onCreate]
*/
fun <T> T.dp(value: Int) where T : Fragment, T : LifecycleOwner = onCreate {
value.toDp(resources.displayMetrics)
}
// In Activity
val margins by dp(5)
from android-ktx.
@romainguy I refined concrete types for these density functions, could you explain why they are not applicable for negative values? (tested myself)
fun Int.toDp(displayMetrics: DisplayMetrics): Float = this.toFloat() / displayMetrics.density
fun Int.toSp(displayMetrics: DisplayMetrics): Float = this.toFloat() / displayMetrics.scaledDensity
fun Float.spToPx(displayMetrics: DisplayMetrics): Int =
(this * displayMetrics.scaledDensity).roundToInt()
fun Float.dpToPx(displayMetrics: DisplayMetrics): Int =
(this * displayMetrics.density).roundToInt()
from android-ktx.
roundToInt()
rounds toward the nearest integer (towards positive infinity when there's a tie), so it won't round in the right direction for negative numbers. For instance 0.5f
rounds to 1, but -0.5f
rounds to 0.
from android-ktx.
from android-ktx.
@romainguy possible fix, round should be ok
fun Float.spToPx(displayMetrics: DisplayMetrics): Int =
(this * displayMetrics.scaledDensity).round()
fun Float.dpToPx(displayMetrics: DisplayMetrics): Int =
(this * displayMetrics.density).round()
private fun Float.round(): Int = (if(this < 0) ceil(this - 0.5f) else floor(this + 0.5f)).toInt()
from android-ktx.
How about a small DSL that would make it possible to write stuff like:
view.context.pixelConversions {
outRect.left = 80.dp
outRect.right = 20.dp
}
Using the idea from the first post, that would be:
fun Context.pixelConversions(block: ConversionContext.() -> Unit) {
block(ConversionContext(resources.displayMetrics))
}
class ConversionContext(private val displayMetrics: DisplayMetrics) {
val Int.dp get() = toFloat().dp.toInt()
val Float.dp get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, displayMetrics)
}
After trying to apply it in a different setting, I'm not sure how useful this idea actually is 🤔
(I forgot this repo is unused now, is this ticket tracked on google issue tracker?)
from android-ktx.
Related Issues (20)
- Convenience DSL for Media Controller Callback event handling
- androidx.preference.PreferenceFragment not derived from androidx.fragment.app.Fragment HOT 2
- Manifest merger failed HOT 5
- Release of 1.0.0-alpha3 out of sync with this repo HOT 4
- Extension property of bitmap from ImageView HOT 1
- error: resource android:attr/fontVariationSettings not found. HOT 1
- ImageDecoder source and test issues HOT 7
- inline extension properties can't be used in SAM lambda functions due to compiler bug HOT 1
- Add popular libraries extensions in new module HOT 1
- AAPT2 Error HOT 1
- View.post with with this view as a parameter HOT 2
- Resources.Theme.resolveAttribute extension
- Improve View.doOnPreDraw(...) HOT 1
- Features suggestions: Live data transformation HOT 1
- Offer: AsyncTask replacement
- Can't use getString(String) : String HOT 2
- androidx.core.os.BundleKt.bundleOf: Imports for API 21 classes break on older devices HOT 2
- gradle error HOT 3
- Add support for manipulating a color as HSV HOT 1
- Hi everyone!
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from android-ktx.