How to Make a Timer in Jetpack Compose - Android Studio Tutorial

Поділитися
Вставка
  • Опубліковано 19 вер 2024

КОМЕНТАРІ • 63

  • @anhtuannd
    @anhtuannd 6 місяців тому +3

    Thank you very much for very comprehensive video. I just have small additional improvement: we can use canvas rotate instead of doing the math with sin/cos.
    The code to draw the handle would be:
    val center = Offset(size.width / 2f, size.height / 2f)
    val r = size.width / 2f
    rotate( 250 * value - 215f, pivot = center) {
    drawPoints(
    listOf(Offset(center.x + r, center.y)),
    pointMode = PointMode.Points,
    color = handleColor,
    strokeWidth = (strokeWidth * 3f).toPx(),
    cap = StrokeCap.Round
    )
    }

  • @fauxvillage3811
    @fauxvillage3811 3 роки тому +3

    Thanks for the video. The work you put into making them useful and efficient is evident.
    A note for those coding along with the video: you may want to get the code first for the sake of seeing which imports are happening -- where Canvas and other components come from matters; also, the "initialValue" parameter is 0.0 to 1.0, representing a proportion of the arc (not realizing this led to some bizarre effects)

  • @amineayachi335
    @amineayachi335 3 роки тому +1

    only 160 likes for such a good content, shame on you guys give this master pieces some love that it deserve and at least buy him a coffee :(

  • @tonnie7079
    @tonnie7079 2 роки тому +1

    Wow On top of learning the mighty Jetpack Compose, I also learnt Trigs functions and the Unit Circle, in another world Philipp would be a Professor of Mathematics!!

  • @rollebonmarquis7574
    @rollebonmarquis7574 Рік тому +6

    Some things I think can be optimized imho:
    1. You don't need to have size as a variable and to have the modifier onSizeChanged. DrawScope has a variable size, so I don't see any reason why not to use this var. Maybe it wasn't present 2 years ago, though.
    2. In regards to the very drawing, given that we initialize a lot of variables during the drawing process, and also given that we do some calculations, it might be better to use the drawWithCache modifier instead of the Canvas composable.
    3. initial value doesn't work right now as a param (at least not functionality wise). To make it work, you may need to define currentTime like this:
    var currentTimeMillis: Long by remember {
    mutableStateOf((initialValue * totalTimeMillis).toLong())
    }
    4. I think the current calculation for the position of the handle doesn't work well when the size is not a square. This might make it work better:
    val centerOffset = Offset(size.width / 2f, size.height/2f)
    val betaAngleDegrees = startAngle + sweepAngle * value
    val betaAngleRadians: Float = (betaAngleDegrees * Math.PI / 180F).toFloat()
    val a: Float = cos(betaAngleRadians) * centerOffset.x
    val b: Float = sin(betaAngleRadians) * centerOffset.y
    val handleOffset = Offset(centerOffset.x + a, centerOffset.y + b)
    5. Mathematically wise, maybe it should have been noted (in case it was not implied) that once you have the start angle, sweep angle on the one hand and this value 145 on the other hand, are not something that you have to experimentally deduce, rather you can get them by doing some simple calculations. In the case of 145, you don't event need it, I think you should be able to safely replace it with start angle (as I do in my code snippet above). So, basically, start angle is something that we decide upon, but sweep angle is something that we get from the start angle with a calculation and 145 can be safely replaced with start angle...
    Other than that, I am very grateful for this content. It would have taken me a loooot of time to build something like this on my own.

    • @anhtuannd
      @anhtuannd 6 місяців тому +1

      Using canvas.rotate would be ideal.
      val center = Offset(size.width / 2f, size.height / 2f)
      val r = size.width / 2f
      rotate( 250 * value - 215f, pivot = center) {
      drawPoints(
      listOf(Offset(center.x + r, center.y)),
      ...
      )
      }

  • @ChrisAthanas
    @ChrisAthanas 3 роки тому +1

    Very helpful, thank you
    This content is underrated and definitely deserves more subs

  • @TheVacuumOfCleaner
    @TheVacuumOfCleaner 2 роки тому +6

    at 19:04 there is a bug: the text of the button will never change to "Restart" because in the if block it checks if the timer is currently running and the current time is greater OR equal to 0. When the time runs out the text of the button will simply be "Stop". To fix this simply remove the "=" sign from the if block

  • @onlinechatter8578
    @onlinechatter8578 3 роки тому

    wow!! Jetpack Compose have lots of tricks in the bag!!!

  • @Blackops1990
    @Blackops1990 Рік тому

    Thx works 100%. @18:02 remove the "=" and the text will fix the bug

  • @pxnx
    @pxnx 3 роки тому +8

    that was neat✨
    How to make a Map in Compose?
    like some vector drawable where you can zoom in, pan/fling and click stuff?

  • @adrianivasku6400
    @adrianivasku6400 6 місяців тому

    Great tutorial, just 100 seconds is almost when measured by a stopwatch 117 seconds.

  • @allisonmcglen5347
    @allisonmcglen5347 2 роки тому

    This video was super helpful to me, as well as many of your other Compose tutorials! Thanks so much Philipp :)

  • @Krushard
    @Krushard Рік тому

    Pretty neat UI work, something to learn from. Treat it as educational, it's not a proper timer because UI lags will screw the actual time keeping, for that you'd need to look into CountDownTimer class.

  • @brigadir5830
    @brigadir5830 Рік тому

    Спасибо за отличные уроки всего вам хорошего👍👍👍

  • @hbemretasci
    @hbemretasci 2 роки тому +1

    It would be appropriate to remove the equality in the if statement so that the restart text appears. :)

  • @rbluejr52
    @rbluejr52 Рік тому

    Great content! This was extremely helpful.

  • @Kunal-jp8tn
    @Kunal-jp8tn 2 роки тому

    Thank you so much for this tutorial.

  • @venkatesh4307
    @venkatesh4307 3 роки тому +1

    Nice 😘😘. I wanna play around with it now 🤗🤗

    • @PhilippLackner
      @PhilippLackner  3 роки тому +5

      That's what she said

    • @fauxvillage3811
      @fauxvillage3811 3 роки тому +1

      @@venkatesh4307 "she" is not a real person, but rather a girlfriend always imagined to be especially appreciative of one's capabilities; it is a frequent form of joke, in response to a set-up, such as "I wanna play with it now"....

    • @venkatesh4307
      @venkatesh4307 3 роки тому

      @@fauxvillage3811 thank you. I don't know English very well. Now, I have understood that 😁😁

  • @AndreuJapan
    @AndreuJapan 2 роки тому +1

    Maybe, you can make a new video explaining how implement that timer inside LazyRow or LazyColum.
    Each item with different time, and when the time expires, remove from list.

  • @Tensordroid
    @Tensordroid 3 роки тому

    Awesome tutorial, thank you so much !

  • @VICMAGUCAS
    @VICMAGUCAS 2 роки тому

    Gracias, tu video me fue de gran utilidad. Deberías publicar un video que muestre como ocultar el ToBar de una que otra pantalla, es decir activity

  • @MrJoker-ze6bb
    @MrJoker-ze6bb 3 роки тому +1

    Please make video on Android canvas basics

  • @douglascf2
    @douglascf2 2 роки тому +2

    if you compare to others timers you will realiza the timer is slow, this is because of the LauncherEffect delay 100, any guess how to improve it?

    • @renanfpedro
      @renanfpedro Рік тому

      It is not because of the LauncherEffect delay 100. But because of the way he is calculating the time. Delaying 100L means you will increase the counter each 100L, but the system also uses some time to do other processes. That is why it is slower.
      The only solution I can see is, instead, to calculate the difference in time from when the user presses the button "Start" to now. This will always be precise, doesn't matter how slow your machine is.

  • @GodlessUkr
    @GodlessUkr 3 роки тому +1

    Would be helpful to know at the beginning of the tutorial if your timer uses the foreground service or not. As it turns out, it's not...
    Why make a timer without a foreground service? It'll only run while the activity is running.

  • @toBeABetterTranslator
    @toBeABetterTranslator 2 роки тому +1

    Intuitive tutorial! Implemented a timer using coroutine delay, but it is not accurate enough, often 3 or 4 seconds lagged behind in a one-minute count. Any idea why is this happening?

    • @mwolfe38
      @mwolfe38 Рік тому

      you may need to alter the delay amount such that it considers what the expected end time is. One way I figured this out is before you delay figure out what time it should be when you delay the the next time (add 1000 to the current system milliseconds time).. And then before you delay the next time figure out the difference between the current time and the expected next time. Usually you end up delaying a bit less than 1000ms each time because of the overhead.

  • @nickb7170
    @nickb7170 3 місяці тому

    How would you go about getting user input to set the start value of the timer?
    And how could you convert that number to minutes/seconds?

    • @zecuse
      @zecuse 2 місяці тому

      For getting user input, I would probably make a text field conditionally replace a text depending if the timer is reset or not. You can get its value when you start the timer and toggle the display condition.
      For converting to minutes and seconds, since the time is retrieved in milliseconds, seconds = (milliseconds / 1000) % 60 and minutes = (milliseconds / 1000 / 60) % 60. The % 60 is to keep the display in the range seconds and minutes usually take when you're viewing time. If you don't want to use hours (add a / 24 in the conversion and % 24 [or % 12 depending if you want to display it as am/pm for some reason]) and allow more than 60 minutes to display, just drop the % 60 from its conversion.

  • @mondoshigua
    @mondoshigua Рік тому

    👋🏼🇨🇴🧔🏻👍🏼🤝🏼 Saludos desde Colombia.

  • @mohitmotwani9256
    @mohitmotwani9256 2 роки тому

    thank you

  • @GauravSharma-ij1ym
    @GauravSharma-ij1ym 6 місяців тому

    What if we rotate screen while timer is going on? Can you make a video to handle this, so that timer continue smoothly even if we change rotation

  • @Kunal-jp8tn
    @Kunal-jp8tn 2 роки тому

    Can you make a full beginner to advance tutorial on Canvas

  • @sercan272727
    @sercan272727 Рік тому

    is it possible to trigger an event from this launched effect to the function calling it? i was trying to trigger something like onTimerDone() , but it never seems to get triggered. I'm beginner with kotlin and android so i might be missing some fundamental
    @Composable
    private fun CountdownTimer(startTime: LocalDateTime, onTimerDone: () -> Unit){
    var timer by remember { mutableStateOf(startTime) }
    var timerIsRunning by remember { mutableStateOf(true) }
    LaunchedEffect(key1 = timer, key2 = timerIsRunning) {
    if (timer == 0L) {
    println("time is done launch effect")
    timerIsRunning = false
    onTimerDone() // not seeing this triggered from composables wrapping this. trying to delegate it all the way to navigation
    } else if (timer > 0 && timerIsRunning) {
    delay(1000L)
    timer -= 1000L
    }
    }
    }

  • @asbhatty
    @asbhatty 2 роки тому

    Mank tanks mate

  • @alirezafaraji
    @alirezafaraji 3 роки тому

    Damn. I was just starting to forget sin & cos shit.

  • @r4ng3l56
    @r4ng3l56 4 дні тому

    no reset button?

  • @abhay2192
    @abhay2192 3 роки тому

    A humble request Sir🙏,
    Sir I have been looking through out the internet, in search of a few things like implementing MVVM pattern, working with Room database(or any remote database) and then working with intents (ie, nearly all the basics of what we knew in *imperative development* ) in jetpack compose...But , I found no help.
    I request you that please consider a few of these topics.
    I'll be thankful to you 🙏

  • @sooshil
    @sooshil Рік тому

    I observed that the timer runs slower than actual time. How can we address that here?

    • @zecuse
      @zecuse 2 місяці тому

      Late reply, but to fix that, you need to use System's currentTimeMillis function to remember when you pressed start and use it again like so: currentTime = currentTimeMillis - start. The delay and value calculation stay the same.

  • @zhanyshmasirov4611
    @zhanyshmasirov4611 2 роки тому

    danke schoon!!!!!!!!!!!!!!!

  • @victorvidican5145
    @victorvidican5145 3 роки тому

    The "reset" text on the button doesn't get updated when the countdown is over. Other than that, great stuff!

    • @tidusmax9669
      @tidusmax9669 3 роки тому +2

      Quick and dirty fix: Change the first if for the Buttontext to: if (isTimerRunning && currentTime > 0L) "Stop"

    • @gauravkumar-bs3pf
      @gauravkumar-bs3pf Рік тому

      Simply you need to remove '=' sign from the if block.

  • @RobertMair80
    @RobertMair80 3 роки тому +1

    Awww 😂

  • @fahadhabibjanjua
    @fahadhabibjanjua 5 місяців тому

    For those watching in 2024
    colors = ButtonDefaults.buttonColors(containerColor =
    if (!isTimerRunning || currentTime

  • @mehulbisht9708
    @mehulbisht9708 3 роки тому

    Well.. how's my countdown timer with compose? 😂 ( Readme has screenshots: github.com/Mehul-Bisht/Jet-Timer )

    • @danielhmorgan
      @danielhmorgan 3 роки тому +1

      Thanks for sharing. (And I apologize for my earlier comment being kind of mean in tone.)

    • @mehulbisht9708
      @mehulbisht9708 3 роки тому +1

      @@danielhmorgan Well back then there weren't as many tutorials and compose had just landed in its Beta. It wouldn't add anything but the countdown timer implementation with an ugly UI would probably be worth a laugh for someone reading it xD