This code demonstrates how to draw a line on a Canvas in an Android application written in Kotlin. The code creates an activity with an ImageView, RadioGroup, and several SeekBars. The SeekBars allow users to control the line's starting and ending points, stroke width, and the cap style (how the ends of the line are drawn).
Breakdown
The MainActivity.kt
file handles the core functionality:
Initialization: It inflates the layout (
activity_main.xml
), retrieves references to UI elements (ImageView, RadioGroup, SeekBars, TextView), and sets initial values for the SeekBars.SeekBar Listener: A generic listener is set for all SeekBars. Whenever the progress of a SeekBar changes (due to user interaction), the
updateDrawing
function is called.updateDrawing: This function performs the following actions:
- Determines the line cap style based on the selected radio button in the RadioGroup.
- Creates a new Bitmap object to serve as the drawing surface.
- Creates a Canvas object associated with the Bitmap.
- Initializes a Paint object with desired properties (anti-aliasing, color, stroke style, stroke width, and cap style).
- Draws the line on the Canvas using
drawLine
with the user-defined starting and ending points obtained from the SeekBar progress values. - Sets the newly created Bitmap as the image source for the ImageView.
- Updates the TextView to display the coordinates of the starting and ending points.
The drawSingleLine
function (defined separately) is responsible for creating the Bitmap, Canvas, Paint object, and drawing the line based on the provided parameters.
The activity_main.xml
file defines the layout of the activity screen, including the ImageView to display the drawn line, a TextView to show the line's coordinates, a RadioGroup to select the line cap style, and several SeekBars to control the line properties.
package com.cfsuman.kotlintutorials
import android.app.Activity
import android.graphics.*
import android.os.Bundle
import android.widget.ImageView
import android.widget.RadioGroup
import android.widget.SeekBar
import android.widget.TextView
class MainActivity : Activity() {
lateinit var imageView: ImageView
lateinit var radioGroup: RadioGroup
lateinit var borderWidth: SeekBar
lateinit var pointX: SeekBar
lateinit var point2X: SeekBar
lateinit var pointY: SeekBar
lateinit var point2Y: SeekBar
lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// get the widgets reference from XML layout
imageView = findViewById(R.id.imageView)
radioGroup = findViewById(R.id.radioGroup)
borderWidth = findViewById(R.id.borderWidth)
pointX = findViewById(R.id.pointX)
pointY = findViewById(R.id.pointY)
point2X = findViewById(R.id.point2X)
point2Y = findViewById(R.id.point2Y)
textView = findViewById(R.id.textView)
borderWidth.max = 100
pointX.max = 1500
pointY.max = 850
point2X.max = 1500
point2Y.max = 850
borderWidth.progress = 20
pointX.progress = 100
pointY.progress = 100
point2X.progress = 600
point2Y.progress = 500
updateDrawing()
setSeekBarChangeListener(borderWidth)
setSeekBarChangeListener(pointX)
setSeekBarChangeListener(pointY)
setSeekBarChangeListener(point2X)
setSeekBarChangeListener(point2Y)
radioGroup.setOnCheckedChangeListener { group, checkedId ->
updateDrawing()
}
}
private fun setSeekBarChangeListener(seekBar: SeekBar){
seekBar.setOnSeekBarChangeListener(
object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(
seekBar: SeekBar?, progress: Int,
fromUser: Boolean) {
updateDrawing()
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
private fun updateDrawing(){
val cap:Paint.Cap = when(radioGroup.checkedRadioButtonId){
R.id.square -> Paint.Cap.SQUARE
R.id.round -> Paint.Cap.ROUND
R.id.but -> Paint.Cap.BUTT
else -> Paint.Cap.SQUARE
}
val bitmap = drawSingleLine(
point = Point(pointX.progress,pointY.progress),
point2 = Point(point2X.progress, point2Y.progress),
strokeWidth = borderWidth.progress.toFloat(),
cap = cap
)
imageView.setImageBitmap(bitmap)
textView.text = "( ${pointX.progress} " +
": ${pointY.progress} )"
textView.append(" ( ${point2X.progress} " +
": ${point2Y.progress} )")
}
}
// function to draw single line on canvas
fun drawSingleLine(
point: Point = Point(150,400),
point2: Point = Point(650, 400),
strokeWidth : Float = 25F,
cap : Paint.Cap = Paint.Cap.SQUARE
):Bitmap?{
val bitmap = Bitmap.createBitmap(
1500,
850,
Bitmap.Config.ARGB_8888
)
// canvas for drawing
val canvas = Canvas(bitmap).apply {
drawColor(Color.parseColor("#A2A2D0"))
}
// paint to draw
val paint = Paint().apply {
isAntiAlias = true
color = Color.parseColor("#333399")
style = Paint.Style.STROKE
this.strokeWidth = strokeWidth
strokeCap = cap
}
// finally, draw the line on canvas
canvas.drawLine(
point.x.toFloat(), // start x
point.y.toFloat(), // start y
point2.x.toFloat(), // stop x
point2.y.toFloat(), // stop y
paint // paint
)
return bitmap
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DCDCDC"
android:padding="24dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView">
<RadioButton
android:id="@+id/square"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cap Square" />
<RadioButton
android:id="@+id/round"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Round"
/>
<RadioButton
android:id="@+id/but"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="But"
/>
</RadioGroup>
<SeekBar
android:id="@+id/borderWidth"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:progressTint="#3F51B5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/radioGroup" />
<SeekBar
android:id="@+id/pointX"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:progressTint="#7BB661"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/borderWidth" />
<SeekBar
android:id="@+id/pointY"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:progressTint="#7BB661"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pointX" />
<SeekBar
android:id="@+id/point2X"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:progressTint="#FF5470"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pointY" />
<SeekBar
android:id="@+id/point2Y"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:progressTint="#FF5470"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/point2X" />
</androidx.constraintlayout.widget.ConstraintLayout>
- android kotlin - Canvas draw text on path
- android kotlin - Canvas draw multiple lines
- android kotlin - Canvas draw arc between two points
- android kotlin - Canvas draw path
- android kotlin - Bitmap mask
- android kotlin - Rounded corners bitmap
- android kotlin - Draw rectangle on bitmap
- android kotlin - Draw text on bitmap
- android kotlin - Bitmap black and white effect
- android kotlin - Bitmap sepia effect
- android kotlin - Base64 string to bitmap
- android kotlin - Bitmap invert colors
- android kotlin - Convert drawable to bitmap
- android kotlin - Display logo on ActionBar
- android kotlin - Get ActionBar height