Kotlin Core Android UI 101

By pjain      Published Dec. 16, 2019, 4:38 a.m. in blog Programming   

kt Andr QUIK Core Andr UI

Configure AS for Kotlin/Andr

  • https://kotlinlang.org/docs/tutorials/kotlin-android.html

  • Configure new project for AS<3.0 - done automatically for AS 3.0+

    • Create new project, and say go to create MainActivity .. for Java
    • OR do Code > Convert Java to Kotlin
      • ADT says need to configure Configure the kotlin, asks () All (x) app module
      • It will do the above two for overall project and module build.gradle ..
  • AS3.0+ IntelliJ kotlin plugin and android kotlin extensions are included and initial template is preset if you check [x] kotlin support

Pre-existing project

  • For pre-existing project you do the following to setup project - note gradle and kotlin versions change rapidly

  • SETUP - config plugin .. a. AS Prefs C-, Plugins .. install Kotlin (auto in AS 3.0x ) b. In project Tools>Kotlin > Config Kotlin In Project - NOTE this is different from older online tutes as Kotlin evolves In popup choose Android With Gradle (version on 7/20/17 was 1.1.3-2) Select Single Module : app to minimize impact on others (can repeat there)

  • In overall project build.gradle - note gradle version 3.0.1 has far better kotlin support buildscript{ ext.kotlin_version = '1.1.3-2' repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.2'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }

  • MODULE build.gradle for app - apply plugin and add kotlin android stdlib for jre7 ..

    apply plugin: 'kotlin-android-extensions' // after apply plugin: 'com.android.application' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" }

  • OPTIONAL - you can have a separate source tree for kotlin files to organize - or mix in same as java paths!

    android { compileSdkVersion 23 buildToolsVersion "23.0.1" sourceSets { main.java.srcDirs += 'src/main/kotlin' } } //AND CREATE it under Project (or os dir)
    app/src/main/kotlin

Convert Java Android projects to Kotlin

  1. Convert 1 Java file

    • Select the file in left project pane and Code> Convert Java file to Kotlin from menu ...
    • IDE will suggest to move new file to the Kotlin folder. Click on ‘Move File’
    • IT IS IMPORTANT to take a look at new .kt file until you understand the differences: IN PATICULAR SEARCH FOR any !! instances and fix them - as they are prone to error!
  2. The bulk converter is iffy, eg the !! assert as not null are bad .. better to convert one by one

TROUBLESHOOTING ADT for Kotlin

  1. Clean project .. rebuild all may be needed to avoid crashing projects

Android Core UI 101

Resources for KT Android

Tutes

@Wrapper Libs

Android Extensions, androidx, ktx

Android Extensions library supports extension properties for View as well as for Activity and Fragment classes.

Just import everything in the `kotlinx.android.synthetic..view package and that’s it. > Official docs for?

  • More extensions
  • https://kotlinlang.org/docs/tutorials/android-plugin.html
  • https://kotlinlang.org/docs/tutorials/android-frameworks.html

  • In module (or top level) build.gradle

    apply plugin: 'kotlin-android-extensions'

Extension functions - needed for EACH class - add to ANY class ~JS prototype

  • You can declare this function anywhere (an utils file for instance), and use it elsewhere as a regular method.

    fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(getActivity(), message, duration).show() } fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, message, duration)
.show() }

    fragment.toast("Hello world!") //simplifies usage onCreate .. toast("in onCreate")

Data binding built in - no extra code

  • This is a KT BUILT IN = does the job of ButterKnife which had BindView annotations

    1) Import kotlinx.android.synthetic.main_activity.* // main/res/layout/activity xml which has ids 2) Get a base view reference (i.e., view you’d otherwise call .findViewById() on) 3) Reference your view like baseView.yourViewId

    import kotlinx.android.synthetic.main.activity_main.* // xml has +id/textView class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) textView.text = "Hello, world!" // even shorter than android call //textView.setText("Hello, world!") // findViewById(R.id.textView) } }

Reified types and Inline functions

These are not strict methods but are inline JVM codes put in, with the inferred type T picked up in the invocation.

onButtonClick(v: View) { navigate&lt;DetailActivity&gt;("2")  }   //? tells where to go to!

inline fun &lt;reified T : Activity&gt; Activity.navigate(id: String) {
    val intent = Intent(this, T::class.java)
    intent.putExtra("id", id)
    startActivity(intent)
}

Inline functions can use reified types, what means that we can recover the class from a type inside the function instead of having to pass the class type as an argument.

Views 101 in Activity

XML Tips

&lt;XXXX: android:id="@+id/text_view_id"  
      android:layout_height="wrap_content"  android:layout_width="wrap_content"  /&gt;

TextView

  &lt;TextView android:id="@+id/tv"  android:text="hello" /&gt;

    tv.text = "Bringing performance enhancements and new features to your apps."
    tv.setSingleLine()
    tv.ellipsize = TextUtils.TruncateAt.MARQUEE
    tv.marqueeRepeatLimit = -1
    tv.isSelected = true

EditText

Change listening

 __et___  ___tv___ &lt;Copy&gt;  - keystroke copies also

    onCreate ..
        et.addTextChangedListener(object :TextWatcher{
            override fun afterTextChanged(s: Editable?) {}
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                tv.text = s
            }
        })
    }
    onCopyClick() { tv.text = et.text }

Button onClick

  • xml -> drives event to activity event handler

  • Other ways to do it are button1.setOnClickListener() { ... logic .. }

Button & Event Listeners in General

  • for RL

    // Simpified activity - all view ids picked up automatically
    import kotlinx.android.synthetic.main.activity_main_activity2.*

    public class MainActivity2 : ActionBarActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main_activity2) tv.text = "Hello Static Import!" tv.setOnClickListener({view->Toast.makeText(this, "Showing Toast", Toast.LENGTH_SHORT).show(); }) } }

  • The listener is same as Java .. tv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(this, "Showing Toast", Toast.LENGTH_SHORT).show(); } });

  • click, long clicke listeners - button example

    lateinit var btn_click_me: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_button)

    btn_click_me = findViewById(R.id.btn_click_me) as Button
    btn_click_me.setOnClickListener(View.OnClickListener{
        btn_click_me.text = "clicked"
    })
    btn_click_me.setOnLongClickListener(View.OnLongClickListener {
        btn_click_me.text = "Long Clicked"
        true
    })
    

Form

Controls Example

Gender ( ) Male ( ) Female

Languages [ ] English [ ] French [ ] Hindi tvanswer_

onSubmitClick() {
    var res = ""
    if(rg_gender.checkedRadioButtonId != -1){
        result +="Selected gender : "
        if(rb_male.isChecked) result += "male\n"
        else if(rb_female.isChecked) result += "female\n"
    }
    result += "Languages Known : "
    if(cb_english.isChecked) result += "English,"
    if(cb_hindi.isChecked) result += "Hindi,"
    if(cb_tamil.isChecked) result += "Tamil"
    tv_answer.text = result
}

Validation

Date, time PICKER

  • /dt/____ <-- or just onClick TV - dt

class MainActivity : AppCompatActivity() { lateinit var dt: TextView //x not need lateinit var pickDate: Button lateinit var cal = Calendar.getInstance() // stores picked date

onCreate{..
    dt = this.tv; // Not needed if in xml: dt!!.text = "__/__/__"
    val dateSetListener = object : DatePickerDialog.OnDateSetListener {
        override fun onDateSet(view: DatePicker, year: Int, monthOfYear: Int, dayOfMonth: Int) {
            cal.set(Calendar.YEAR, year)
            cal.set(Calendar.MONTH, monthOfYear)
            cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
            updateDateInView()
        }
    }
}
fun onPickDate(v: View) {
            // set DatePickerDialog to point to today's date when it loads up
    DatePickerDialog(this@MainActivity, dateSetListener,
                     cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH))
                .show()
}
private fun updateDateInView() {
    val myFormat = "MM/dd/yyyy" // mention the format you need
    val sdf = SimpleDateFormat(myFormat, Locale.US)
    dt!!.text = sdf.format(cal.getTime())
}

Spinner PICKER

  • Ex [ option ]v tv_
    lateinit var option : Spinner   //?PKJ are these necessary?
    lateinit var result : TextView
    

    onCreate... val options = arrayOf("Option 1", "Option 2","Option 3") option!!.adapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,options) option!!.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) option!!.setOnItemSelectedListener(this); } override fun onNothingSelected(parent: AdapterView<>?) { tv.text = "Please Select an Option" } override fun onItemSelected(parent: AdapterView<>?, view: View?, position: Int, id: Long) { tv.text = options.get(position) }

Seekbar

  • Ex ---(slider)---- value_ status

    lateinit var slider : SeekBar   //PKJ these ARE necessary even with synthetic for concreteness
    lateinit var value : TextView
    lateinit var status : TextView
    

    onCreate .. //Code is very similar progress = this.progress //PKJ- do we NEED TO DO THIS as vars are declared outside onCreate?? status = this.status slider = this.slider

    slider.max = 50 //By default, the range of progress is [0,100] in steps of 1.
    slider.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
            value.text = progress.toString()
            status.text = "Seeking to : " + progress.toString()
        }
        override fun onStartTrackingTouch(seekBar: SeekBar) {
            status.text = "started at : " + seekBar.progress
        }
        override fun onStopTrackingTouch(seekBar: SeekBar) {
            status.text = "selected : " + seekBar.progress
        }
    })
    

    //or can shift event handling to activity - but not advisable if multiple seekbars and it clutters up this.seekbar!!.setOnSeekBarChangeListener(this)

  • Custom range, steps with progress view val MIN=10; val MAX=160; val STEP=5 seekbar!!.setMax((MAX-MIN)/STEP) //default 0-100 step 1 ..

Checkbox

&lt;TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Languages Known" /&gt;
&lt;LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:orientation="vertical"&gt;
    &lt;CheckBox android:id="@+id/cb_english" android:text="English"  android:layout_width="match_parent" android:layout_height="wrap_content"/&gt;
    &lt;CheckBox android:id="@+id/cb_hindi" android:text="Hindi" android:layout_width="match_parent" android:layout_height="wrap_content" /&gt;
    &lt;CheckBox android:id="@+id/cb_tamil" android:text="Tamil" android:layout_width="match_parent" android:layout_height="wrap_content" /&gt;
&lt;/LinearLayout&gt;

Radio

&lt;TextView android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Gender" /&gt;
&lt;RadioGroup android:id="@+id/rg_gender" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="10dp"&gt;
    &lt;RadioButton android:id="@+id/rb_male" android:text="Male"  android:layout_width="match_parent" android:layout_height="wrap_content"/&gt;
    &lt;RadioButton android:id="@+id/rb_female" android:text="Female" android:layout_width="match_parent" android:layout_height="wrap_content"/&gt;
&lt;/RadioGroup&gt;

Lists

LISTy 101

ListView BPR - custom Adapters, XML views, ViewHolder pattern

CardView

RecyclerView

Cardy


0 comments

There are no comments yet

Add new comment

Similar posts

Serverless Computing

Android Layouts Design 101

Drawing, Canvas in Kotlin

Custom Views