Lab 2
Introduction
In this lab we will try our first steps with the Kotlin language and add basic interactive behaviour, such as click handling, to our UI.
- Make sure you have an understanding of these Kotlin concepts, discussed during the lecture:
- Mutable and immutable variable declaration (var vs val)
- Null-safety, including safe calls and the !! operator
- Inferred types
Exercise 1: In-code GUI creation
in MainActivity.kt onCreate():
- Create an instance of the LinearLayout class. The primary constructor expects a Context type argument, you can use the this keyword (which points to the current Activity instance).
- Set it to be vertical by updating the value of its' orientation
- Add 10 buttons to it using a loop ( Feel free to try out different ways to achieve this with Kotlin, e.g. with for loops or using repeat )
- Update the loop so that the attributes of each button are modified:
- Set the text of each one to "Button X", where X is an integer representing current iteration number within the loop.
- Set the background of the buttons to a color based on the iteration number. You can do this with
setBackgroundColor(Color.rgb( red, green, blue))
, where the 3 arguments are values between 0-255 for each of the 3 color channels.
- Make the Activity display the LinearLayout object instead of the default XML resource (using setContentView(..) ).
Exercise 2: ConstraintLayout practice
Change back your MainActivity so that it uses the XML resource activity definition. Create the following ConstraintLayout configuration:
- Divide the UI vertically into 2 (2/3 and 1/3, as shown on picture), using a Guideline in percentage mode
- Top should have 1 TextView with long text
- Vertically centered w.r.t. guideline
- Horizontally constrained to edges of layout, with 32dp margin
- Add 2 Buttons to the bottom
- Vertically centered
- Create a horizontal chain of them
- Set chain to "packed"
- Horizontally constrainted to edges of the parent
Exercise 3: Click behaviour
- Set up a click handler for both buttons (see below for more details)
- For the 1st button, use the programmatic approach and make the click update the button to show the number of times it has been clicked. Each time it gets clicked, it should also add a word to the TextView (hint: use TextView.append(..) or Kotlin repeat).
- For the 2nd button, use
XML onClick
and make it restart the counter. (Also try clearing the TextView)
You can achieve this based on the below tips:
Getting a reference to a UI element defined in XML
- you can access UI View Objects directly using its ID: e.g. if your XML object has an ID of myButton, in Kotlin you can refer to it directly:
myButton.text = "Hello"
- have to import
import kotlinx.android.synthetic.main.activity_main
where activity_main correspond to the activity you are working with. - ( this works thanks to View Binding of the Kotlin Android Extension)
- have to import
- alternatively, using the findViewById(..) method, you can get a handle for referencing XML-declared resources & view objects in code:
val b:Button = findViewById(R.id.myButton)
- this is the common approach in Java-based Android
Setting click listeners
- To set a click listener from the code, you can use Button.setOnClickListener( .. )
button1.setOnClickListener { view: View? -> Log.i(TAG, "View: ${view?.id} was clicked!") }
- Alternatively, you can specify android:onClick attribute of the XML object definition, setting its value to the name of the method to be called
- The method has to be defined in the Activities' .kt file and accept a single argument of type View:
fun myHandler(view: View) { /** react to click */ }
- The method has to be defined in the Activities' .kt file and accept a single argument of type View:
Exercise 4: Touch listener
Let's add more fine-grained control of button presses using a touch listener. With a touch listener, we can differentiate the moment when the button is pressed down and when it is released.
The basic code for attaching a touch listener looks like this:
my_button.setOnTouchListener({ view, motionEvent -> // do something useful true // return value - whether this listener consumed the event })
In the above, the return value indicates whether or not this listener consumed the event (if you set it false and also have a click listener for the same button, the click listener also gets triggered, whereas if the touch listener consumes the event, the click listener won't get triggered).
the motionEvent
can be used to determine which kind of touch event it is.
Let's handle two kinds of events: DOWN and UP using Kotlin's when construct:
when (motionEvent.action){ MotionEvent.ACTION_UP -> { /** TODO */ } MotionEvent.ACTION_DOWN -> { /** TODO */ } else -> { /** something else happened */} }
- You may see a warning about not calling performClick(), you can ignore it for this lab, but here is a good explanation of the warning.
- Replace the TextView in your ConstraintLayout with a vertical LinearLayout (in the XML layout file).
- Using the onTouchListener, record how long the button was held down in milliseconds (use System.currentTimeMillis() )
- Whenever the button is released and you have the press duration, add a new TextView to the LinearLayout
- Make the textview display the duration
- To empty the LinearLayout (for the reset button), you can use
my_layout.removeAllViews()