{"id":3893,"date":"2025-06-01T11:21:30","date_gmt":"2025-06-01T11:21:30","guid":{"rendered":"https:\/\/alsaeeddev.com\/?p=3893"},"modified":"2025-06-01T11:21:30","modified_gmt":"2025-06-01T11:21:30","slug":"stunning-custom-analog-clock-in-android-java-kotlin","status":"publish","type":"post","link":"https:\/\/alsaeeddev.com\/shop\/stunning-custom-analog-clock-in-android-java-kotlin\/","title":{"rendered":"Stunning Custom Analog Clock in Android \u2013 Java &#038; Kotlin"},"content":{"rendered":"<p>Want to design a <strong>custom analog clock in Android<\/strong>? In this post, you&#8217;ll learn how to create one using both Java and Kotlin. Whether you&#8217;re building a utility app, dashboard UI, or simply improving your UI skills, this is the perfect project to implement a working analog clock in Android.<\/p>\n<h3>\ud83c\udfaf What\u2019s Inside This Project?<\/h3>\n<p>You\u2019ll get the complete source code for both languages, canvas-based drawing, second-by-second ticking hands, and a beautiful rounded design. Let\u2019s dive into development!<\/p>\n<h3>\u2705 What You&#8217;ll Learn<\/h3>\n<ul>\n<li>How to draw a custom analog clock using Canvas<\/li>\n<li>Java and Kotlin implementations side by side<\/li>\n<li>Center dot, circular frame, and dynamic ticking hands<\/li>\n<li>Modern, responsive UI layout for all screen sizes<\/li>\n<\/ul>\n<p>This article provides two versions: <code>AnalogClockView.java<\/code> and <code>AnalogClockViewKotlin.kt<\/code>. You can use either based on your language preference.<\/p>\n<h3>\ud83d\udcc4 XML Layout<\/h3>\n<p>To use the custom clock in your activity, add this to your <code>activity_main.xml<\/code>:<\/p>\n<pre><code class=\"language-xml\">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\r\n&lt;RelativeLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    xmlns:tools=\"http:\/\/schemas.android.com\/tools\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    tools:context=\".MainActivity\"&gt;\r\n\r\n    &lt;www.alsaeeddev.clock.AnalogClockView\r\n        android:id=\"@+id\/analogClock\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"match_parent\"\r\n        android:layout_centerInParent=\"true\" \/&gt;\r\n\r\n&lt;\/RelativeLayout&gt;\r\n<\/code><\/pre>\n<h3>\ud83d\udce6 Java Code: AnalogClockView.java<\/h3>\n<pre><code> \r\npackage www.alsaeeddev.clock;\r\nimport android.content.Context;\r\nimport android.graphics.Canvas;\r\nimport android.graphics.Color;\r\nimport android.graphics.Paint;\r\nimport android.graphics.Rect;\r\nimport android.util.AttributeSet;\r\nimport android.view.View;\r\n\r\nimport java.util.Calendar;\r\n\r\npublic class AnalogClockView extends View {\r\n\r\n    private Paint paint;\r\n    private int width, height, radius;\r\n    private int padding = 0;\r\n    private int numeralSpacing = 30;\r\n    private int handTruncation, hourHandTruncation;\r\n    private final int[] numbers = {1,2,3,4,5,6,7,8,9,10,11,12};\r\n    private Rect textBounds = new Rect();\r\n\r\n    public AnalogClockView(Context context) {\r\n        super(context);\r\n        init();\r\n    }\r\n\r\n    public AnalogClockView(Context context, AttributeSet attrs) {\r\n        super(context, attrs);\r\n        init();\r\n    }\r\n\r\n    private void init() {\r\n        paint = new Paint();\r\n    }\r\n\r\n    @Override\r\n    protected void onDraw(Canvas canvas) {\r\n        width = getWidth();\r\n        height = getHeight();\r\n        int min = Math.min(width, height);\r\n        radius = min \/ 2 - 40;\r\n\r\n        canvas.drawColor(Color.parseColor(\"#928dab\")); \/\/ Background\r\n\r\n        \/\/ Draw clock background\r\n        paint.reset();\r\n        paint.setColor(Color.parseColor(\"#b3f6f8\"));\r\n        paint.setStyle(Paint.Style.FILL);\r\n        canvas.drawCircle((float) width \/2, (float) height \/2, radius + 30, paint);\r\n\r\n        paint.setStyle(Paint.Style.STROKE);\r\n        paint.setColor(Color.parseColor(\"#9e7419\"));\r\n        paint.setStrokeWidth(8f);\r\n        canvas.drawCircle((float) width \/2, (float) height \/2, radius + 30, paint);\r\n\r\n        \/\/ Draw center dot\r\n        paint.setStyle(Paint.Style.FILL);\r\n        paint.setColor(Color.BLACK);\r\n        canvas.drawCircle((float) width \/2, (float) height \/2, 12, paint);\r\n\r\n        \/\/ Draw clock numbers\r\n        paint.setTextSize(40);\r\n        paint.setColor(Color.BLACK);\r\n        for (int number : numbers) {\r\n            String tmp = String.valueOf(number);\r\n            paint.getTextBounds(tmp, 0, tmp.length(), textBounds);\r\n            double angle = Math.PI \/ 6 * (number - 3);\r\n            int x = (int)((double) width \/2 + Math.cos(angle) * (radius - numeralSpacing) - (double) textBounds.width() \/2);\r\n            int y = (int)((double) height \/2 + Math.sin(angle) * (radius - numeralSpacing) + (double) textBounds.height() \/2);\r\n            canvas.drawText(tmp, x, y, paint);\r\n        }\r\n\r\n        \/\/ Get time\r\n        Calendar calendar = Calendar.getInstance();\r\n        int hour = calendar.get(Calendar.HOUR);\r\n        int minute = calendar.get(Calendar.MINUTE);\r\n        int second = calendar.get(Calendar.SECOND);\r\n\r\n        drawHand(canvas, (hour + minute \/ 60.0) * 5f, true, false); \/\/ Hour hand\r\n        drawHand(canvas, minute, false, false);                     \/\/ Minute hand\r\n        drawHand(canvas, second, false, true);                      \/\/ Second hand\r\n\r\n        postInvalidateDelayed(1000);\r\n        invalidate();\r\n    }\r\n\r\n\r\n\r\n\/\/ draw the clock hands\r\n    private void drawHand(Canvas canvas, double loc, boolean isHour, boolean isSecond) {\r\n        double angle = Math.PI * loc \/ 30 - Math.PI \/ 2;\r\n        int handRadius = isHour ? radius - 120 : radius - 60;\r\n        if (isSecond) handRadius = radius - 40;\r\n\r\n        paint.setColor(isSecond ? Color.parseColor(\"#e74c3c\") : Color.BLACK);\r\n        paint.setStrokeWidth(isSecond ? 4f : isHour ? 8f : 6f);\r\n        canvas.drawLine((float) width \/2, (float) height \/2,\r\n                (float)((double) width \/2 + Math.cos(angle) * handRadius),\r\n                (float)((double) height \/2 + Math.sin(angle) * handRadius),\r\n                paint);\r\n    }\r\n}\r\n<\/code><\/pre>\n<h3>\ud83e\uddd1\u200d\ud83d\udcbb Kotlin Code: AnalogClockViewKotlin.kt<\/h3>\n<pre><code> \r\npackage www.alsaeeddev.clock\r\n\r\nimport android.content.Context\r\nimport android.graphics.Canvas\r\nimport android.graphics.Color\r\nimport android.graphics.Paint\r\nimport android.graphics.Rect\r\nimport android.util.AttributeSet\r\nimport android.view.View\r\nimport java.util.Calendar\r\nimport kotlin.math.cos\r\nimport kotlin.math.min\r\nimport kotlin.math.sin\r\n\r\nclass AnalogClockViewKotlin @JvmOverloads constructor(\r\n    context: Context, attrs: AttributeSet? = null\r\n) : View(context, attrs) {\r\n\r\n    private val paint = Paint()\r\n    private val numbers = (1..12).toList()\r\n    private val textBounds = Rect()\r\n    private var widthCenter = 0\r\n    private var heightCenter = 0\r\n    private var radius = 0\r\n\r\n    init {\r\n        paint.isAntiAlias = true\r\n    }\r\n\r\n    override fun onDraw(canvas: Canvas) {\r\n        super.onDraw(canvas)\r\n\r\n        widthCenter = width \/ 2\r\n        heightCenter = height \/ 2\r\n        radius = min(widthCenter, heightCenter) - 60\r\n\r\n        drawBackground(canvas)\r\n        drawCenterDot(canvas)\r\n        drawNumbers(canvas)\r\n        drawHands(canvas)\r\n\r\n        postInvalidateDelayed(1000)\r\n        invalidate()\r\n    }\r\n\r\n    private fun drawBackground(canvas: Canvas) {\r\n        paint.reset()\r\n        paint.isAntiAlias = true\r\n\r\n        \/\/ Clock circle fill\r\n        paint.color = Color.parseColor(\"#b3f6f8\")\r\n        paint.style = Paint.Style.FILL\r\n        canvas.drawCircle(widthCenter.toFloat(), heightCenter.toFloat(), radius + 30f, paint)\r\n\r\n        \/\/ Clock border\r\n        paint.style = Paint.Style.STROKE\r\n        paint.strokeWidth = 8f\r\n        paint.color = Color.parseColor(\"#9e7419\")\r\n        canvas.drawCircle(widthCenter.toFloat(), heightCenter.toFloat(), radius + 30f, paint)\r\n    }\r\n\r\n    private fun drawCenterDot(canvas: Canvas) {\r\n        paint.style = Paint.Style.FILL\r\n        paint.color = Color.BLACK\r\n        canvas.drawCircle(widthCenter.toFloat(), heightCenter.toFloat(), 12f, paint)\r\n    }\r\n\r\n    private fun drawNumbers(canvas: Canvas) {\r\n        paint.textSize = 40f\r\n        paint.color = Color.BLACK\r\n        for (number in numbers) {\r\n            val numStr = number.toString()\r\n            paint.getTextBounds(numStr, 0, numStr.length, textBounds)\r\n            val angle = Math.PI \/ 6 * (number - 3)\r\n            val x = (widthCenter + cos(angle) * (radius - 30) - textBounds.width() \/ 2).toFloat()\r\n            val y = (heightCenter + sin(angle) * (radius - 30) + textBounds.height() \/ 2).toFloat()\r\n            canvas.drawText(numStr, x, y, paint)\r\n        }\r\n    }\r\n\r\n    private fun drawHands(canvas: Canvas) {\r\n        val calendar = Calendar.getInstance()\r\n        val hour = calendar.get(Calendar.HOUR)\r\n        val minute = calendar.get(Calendar.MINUTE)\r\n        val second = calendar.get(Calendar.SECOND)\r\n\r\n        drawHand(canvas, (hour + minute \/ 60f) * 5, isHour = true, isSecond = false)\r\n        drawHand(canvas, minute.toFloat(), isHour = false, isSecond = false)\r\n        drawHand(canvas, second.toFloat(), isHour = false, isSecond = true)\r\n    }\r\n\r\n    private fun drawHand(canvas: Canvas, loc: Float, isHour: Boolean, isSecond: Boolean) {\r\n        val angle = Math.PI * loc \/ 30 - Math.PI \/ 2\r\n        val handLength = when {\r\n            isHour -&gt; radius - 120\r\n            isSecond -&gt; radius - 30\r\n            else -&gt; radius - 60\r\n        }\r\n\r\n        paint.color = if (isSecond) Color.parseColor(\"#e74c3c\") else Color.BLACK\r\n        paint.strokeWidth = when {\r\n            isHour -&gt; 8f\r\n            isSecond -&gt; 4f\r\n            else -&gt; 6f\r\n        }\r\n        paint.style = Paint.Style.STROKE\r\n\r\n        canvas.drawLine(\r\n            widthCenter.toFloat(), heightCenter.toFloat(),\r\n            (widthCenter + cos(angle) * handLength).toFloat(),\r\n            (heightCenter + sin(angle) * handLength).toFloat(),\r\n            paint\r\n        )\r\n    }\r\n}\r\n\r\n<\/code><\/pre>\n<hr \/>\n<p><iframe loading=\"lazy\" title=\"\ud83d\udd25 Custom Analog Clock in Android | Java &amp; Kotlin UI Design #shorts #androidappdevelopment\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/KSu9KR-Yvkc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<hr \/>\n<h3>\u2705 Conclusion<\/h3>\n<p>Creating a custom analog clock in Android is a great way to explore Canvas drawing, custom views, and elegant UI development. Whether you choose Java or Kotlin, the outcome is a clean and dynamic clock component ready for your next project.<\/p>\n<p>We used the Paint class extensively to draw shapes and text on the canvas. To learn more about its capabilities, see the official documentation here:<br \/>\n\ud83d\udd17 <a href=\"https:\/\/developer.android.com\/reference\/android\/graphics\/Paint\" target=\"_blank\" rel=\"noopener noreferrer\">Android Developers<\/a><\/p>\n<p><strong>Don\u2019t forget to share and follow <a href=\"https:\/\/alsaeeddev.com\/blog\">Al Saeed<\/a> for more hands-on Android tutorials.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Want to design a custom analog clock in Android? In this post, you&#8217;ll learn how to create one using both Java and Kotlin. Whether you&#8217;re building a utility app, dashboard UI, or simply improving your UI skills, this is the perfect project to implement a working analog clock in Android. \ud83c\udfaf What\u2019s Inside This Project? [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3902,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,117,116,164],"tags":[166,167,176,170,169,168,174,175,102,171,165,172,173],"class_list":["post-3893","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-java","category-kotlin","category-source-codes","tag-analog-clock-in-android-java","tag-analog-clock-in-android-kotlin","tag-analog-clock-project-android","tag-analog-clock-source-code","tag-android-canvas-drawing","tag-android-custom-view-tutorial","tag-android-graphics-tutorial","tag-android-paint-class","tag-android-ui-design","tag-build-analog-clock-android","tag-custom-analog-clock-android","tag-java-analog-clock-example","tag-kotlin-analog-clock-view"],"_links":{"self":[{"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/posts\/3893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/comments?post=3893"}],"version-history":[{"count":13,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/posts\/3893\/revisions"}],"predecessor-version":[{"id":4031,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/posts\/3893\/revisions\/4031"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/media\/3902"}],"wp:attachment":[{"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/media?parent=3893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/categories?post=3893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alsaeeddev.com\/shop\/wp-json\/wp\/v2\/tags?post=3893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}