Android application development (supports both Java and Kotlin) How do you implement this? ~ Text Edition ~

This article is the second part of "Android application development: how do you implement this?"

The main target is (arbitrarily) assuming "beginners and intermediates who have learned to google" like me. Since it explains both Java and Kotlin, even those who say "I understand the implementation in Java, but how do you write it in Kotlin?" I think it will be useful.

The first was Button Edition.

A sample of this project can be found at the link below. The master branch is the Kotlin source code and the java branch is the Java source code.

https://github.com/Dai1678/SampleCodePrograms

I tried using various Texts

There is no tsukkomi that you are already using Text in the first time. That's an essential function.

It's just boring to just put a TextView As a sample

--TextView that can be copied by long-pressing the character --Only here is ordinary EditText --Text Clock found by some kind of completion function ――TexInputLayout / EditText that everyone loves Material Design can be easily created

In addition, I added a function like a simple login form using these.

environment

Android Studio 3.0+ Confirmed operation on Android 8.0

build.gradle


apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "net.ddns.dai.samplecodeprograms"
        minSdkVersion 17
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:27.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:design:27.1.0'
    implementation 'com.android.support:customtabs:27.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

Operation demo

TextSampleActivity.gif

XML description

activity_text_sample.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="10dp"
    tools:context=".TextSampleActivity">

    <TextView
        android:id="@+id/userName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Your username is ◯◯\n Press and hold to copy"
        android:textSize="20sp"
        android:textIsSelectable="true"/>

    <EditText
        android:id="@+id/editPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Please set a password"
        android:textSize="20sp"
        android:maxLines="1"
        android:layout_marginTop="20dp" />

    <TextClock
        android:id="@+id/currentTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:hint="yyyy/MM/dd HH:mm:ss"
        android:textSize="20sp"
        android:timeZone="Asia/Tokyo"
        android:format12Hour="yyyy/MM/dd HH:mm:ss"
        android:format24Hour="yyyy/MM/dd HH:mm:ss"/>

    <android.support.design.widget.TextInputLayout
        android:id="@+id/nameTextInputLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:counterEnabled="true"
        app:counterMaxLength="10"
        app:errorEnabled="true"
        app:hintAnimationEnabled="true"
        app:hintEnabled="true">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/userNameInput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="username"
            android:maxLines="1"
            android:textSize="20sp" />

    </android.support.design.widget.TextInputLayout>


    <android.support.design.widget.TextInputLayout
        android:id="@+id/passwordTextInputLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:counterEnabled="false"
        app:errorEnabled="false"
        app:hintAnimationEnabled="true"
        app:hintEnabled="true">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/userPassWordInput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="textPassword"
            android:hint="password"
            android:maxLines="1"
            android:textSize="20sp" />

    </android.support.design.widget.TextInputLayout>

    <Button
        android:id="@+id/loginButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Login"/>

</LinearLayout>

You can display characters with <TextView />.

--ʻ android: The recommended unit for textSizeissp. It expands and contracts depending on the font size setting of the terminal. --When android: textIsSelectable is set to true, you can select the range by tapping the displayed character.

You can enter characters with <EditText />.

―― ʻandroid: hint allows you to set a string that prompts the user to enter when nothing is entered. (In TextView etc., it is used for checking on the Preview screen of Android Studio) --When you start a new line while typing with ʻandroid: maxLines, the input space is expanded only to the specified number of lines. (Actually, the line breaks just because the characters disappear)

<TextClock /> can display the current date and time as a formatted string.

Use <TextInputLayout /> and <TextInputEditText /> as a set (when preparing two input fields, prepare two each). You can use this to implement EditText with material design animations.

Don't forget ʻimplementation'com.android.support: design: (version)in build.gradle when using it. Also, when using app: ~ in xml, don't forgetxmlns: app =" http://schemas.android.com/apk/res-auto "`.

--When ʻapp: counterEnabled is set to true, the number of characters entered is displayed in the lower right corner. --If you specify ʻapp: counterMaxLength, you can visualize the character limit like 0/10. (With this alone, you can continue typing even if the number of characters is exceeded) --When ʻapp: errorEnabled is set to true --If ʻapp: hintEnabled is set to true, the hint string is displayed in the upper left while typing. --ʻApp: If hintAnimationEnabled` is set to true, the animation will be applied to the hint string.

Explanation of Activity

Java edition

It is often used when dealing with the characters displayed or entered in TextView or EditText. getText and setText.

example.java


 //Since the return value of getText is TextView type, Cast with toString etc.(Type conversion)And substitute
String str = textView.getText().toString();

textView.setText("String");

TextInputEditText is basically the same usage.

In the sample, generate a 10-digit random number with the generateUserName method and decide the user name arbitrarily. Set the password with any character string in EditText with the hint of "Please set the password". When the login button is pressed, the character string is compared with the character string entered in TextInputEditText that has the hints of "user name" and "password".

About TextInputLayout and TextInputEditText

I wanted to use EditText, which is material design, so I tried it.

Basically, if you add it to xml, it will work without permission, but On the code side, if more than the number of ʻapp: counterMaxLength` specified in xml is entered An error message was displayed.

example.java


userNameInput.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
                if (charSequence.length() > nameTextInputLayout.getCounterMaxLength()){
                    nameTextInputLayout.setError("Please enter the user name within 10 characters");
                }else{
                    nameTextInputLayout.setError(null);
                }
            }


        });

userNameInput will be the TextInputLayout where you enter your user name. I've added a Listener to this to monitor the characters typed in TextWatcher.

beforeTextChanged(CharSequence charSequence, int start, int count,int after)

--Method called just before the string is modified - CharSequence charSequence
The string currently entered in EditText - int start
Start position of the newly added character string in the charSequence character string - int count
Total number of changed strings in the charSequence string - int after
Number of newly added strings

onTextChanged(CharSequence charSequence, int start, int before, int count)

--Called when one character is entered - CharSequence charSequence
The string currently entered in EditText - int start
Start position of the newly added character string in the charSequence character string - int before
Number of existing strings to be deleted - int count
Total number of changed strings in the charSequence string

afterTextChanged(Editable editable)

--Finally this method is called - Editable editable
The final modifiable, modified string

To display the error message, use the setError method, and if nothing is displayed, specify null as an argument.

I have omitted explanations other than those related to text, but the following is the source code.

TextSampleActivity.java


public class TextSampleActivity extends AppCompatActivity {

    private final int NoInput = -2;
    private final int LOGIN = 1;
    private final int ERROR = -1;

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_sample);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        final String name = generateUserName();

        TextView userName = findViewById(R.id.userName);
        userName.setText("Your username is" + name + "is\n Press and hold to copy");

        Button loginButton = findViewById(R.id.loginButton);
        final EditText editPassWord = findViewById(R.id.editPassword);
        final TextInputEditText userNameInput = findViewById(R.id.userNameInput);
        final TextInputEditText userPassWordInput = findViewById(R.id.userPassWordInput);

        final TextInputLayout nameTextInputLayout = findViewById(R.id.nameTextInputLayout);

        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String yourPassWord = editPassWord.getText().toString();
                String inputUserName = userNameInput.getText().toString();
                String inputUserPassWord = userPassWordInput.getText().toString();

                if (inputUserName.equals("")){
                    //Prompt for yourPassWord
                    showResult(view, NoInput);
                }else{
                    boolean loginResult = name.equals(inputUserName) && yourPassWord.equals(inputUserPassWord);

                    if (loginResult){
                        //login
                        showResult(view, LOGIN);
                    }else{
                        //error
                        showResult(view, ERROR);
                    }
                }

            }
        });

        userNameInput.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
                if (charSequence.length() > nameTextInputLayout.getCounterMaxLength()){
                    nameTextInputLayout.setError("Please enter the user name within 10 characters");
                }else{
                    nameTextInputLayout.setError(null);
                }
            }


        });

    }

    private String generateUserName(){

        final String letters = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder();

        while (stringBuilder.length() < 10){
            int val = random.nextInt(letters.length());
            stringBuilder.append(letters.charAt(val));
        }

        return stringBuilder.toString();

    }

    @SuppressLint("SimpleDateFormat")
    private void showResult(View view, int result){

        String showText = "";
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date date = new Date(System.currentTimeMillis());

        switch (result){
            case NoInput:
                showText = "Please set a password";
                break;

            case LOGIN:
                showText = dateFormat.format(date) + "You logged in to!";
                break;

            case ERROR:
                showText = "The user name or password entered is incorrect";
        }

        Snackbar.make(view, showText, Snackbar.LENGTH_LONG)
                .setAction("Action", null).show();

    }
}

Why did I have to add the final modifier to the variables named editPassWord, userNameInput, userPassWordInput? This is to prevent the value from being changed during processing such as OnClickListener that defines an anonymous class. If you want to do something like count-up during processing, you can use the member variables of the class.

Kotlin edition

The way to write getText and setText in Kotlin is a little cool.

example.kt


val str = textView.text.toString()  //Used as setText

textView.text = "String"  //Used as getText

You can do both with .text. Especially when using it as getText, instead of passing a String type as an argument like java It is expressed in the form of substitution.

As an aside, in Kotlin, when you want to embed a variable in a string, you can express it naturally by using $. It's the same as PHP.

example.kt


userName.text = "Your username is${name}is\n Press and hold to copy"

//This is fine when putting spaces before and after the variable
userName.text = "Your username is$is name\n Press and hold to copy" 

Below is the source code of the sample app in Kotlin.

TextSampleActivity.kt


class TextSampleActivity : AppCompatActivity() {

    private val noInput = -2
    private val login = 1
    private val error = -1

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_text_sample)

        val actionBar = supportActionBar
        actionBar!!.setDisplayHomeAsUpEnabled(true)

        //Create yourName
        val name = generateUserName(10)
        userName.text = "Your username is${name}is\n Press and hold to copy"

        loginButton.setOnClickListener { view ->
            val yourPassWord = editPassword.text.toString()
            val inputUserName = userNameInput.text.toString()
            val inputUserPassWord = userPassWordInput.text.toString()

            if (inputUserPassWord == ""){
                //Prompt for yourPassWord
                showResult(view, noInput)
            }else{
                val loginResult = name == inputUserName && yourPassWord == inputUserPassWord

                if (loginResult){
                    //login
                    showResult(view, login)
                }else{
                    //error
                    showResult(view, error)
                }
            }

        }

        userNameInput.addTextChangedListener(object: TextWatcher {
            override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) {}
            override fun afterTextChanged(editable: Editable) {}
            override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
                if (charSequence.length > nameTextInputLayout.counterMaxLength) {
                    nameTextInputLayout.error = "Please enter the user name within 10 characters"
                } else {
                    nameTextInputLayout.error = null
                }
            }
        })

    }

    //Random number creation with the number of digits of the argument value
    private fun generateUserName(length: Int): String {

        val letters = "abcdefghijklmnopqrstuvwxyz0123456789"

        var str = ""
        while (str.length < length) {
            str += letters[Random().nextInt(letters.length)]
        }

        return str

    }

    @SuppressLint("SimpleDateFormat")
    private fun showResult(view: View, result: Int){

        var showText = ""
        val dateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
        val date = Date(System.currentTimeMillis())

        when (result) {
            noInput -> {
                showText = "Please set a password"
            }
            login -> {
                showText = "${dateFormat.format(date)}You have logged in to!"
            }
            error -> {
                showText = "The user name or password entered is incorrect"
            }
        }

        Snackbar.make(view, showText, Snackbar.LENGTH_LONG)
                .setAction("Action", null).show()

    }
}

reference

I learned about TextInputLayout based on this article. -Android --Text field implementation with TextInputLayout

Next time preview

I've used it many times already, but about Toast and Snack Bar. Maybe I'll omit it and do something else ...

It's not out of material

Afterword

I would like to show it to juniors at the university, but I would be grateful if Qiita users could comment if there is demand. If you have any mistakes, please make a correction request.

Recommended Posts

Android application development (supports both Java and Kotlin) How do you implement this? ~ Text Edition ~
Android application development (supports both Java and Kotlin) How do you implement this? ~ Button edition ~
Summary of good points and precautions when converting Java Android application to Kotlin