Mobile App Dev 2022W: Tutorial 9

From Soma-notes
Revision as of 17:40, 22 March 2022 by Soma (talk | contribs) (Created page with "==Code== ===[https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/PicViewer2/MainActivity.kt MainActivity.kt]=== <syntaxhighlight lang="kotlin" line> package carleton.comp1601.remotepicview2 import android.os.Bundle import android.text.Editable import android.text.TextWatcher import android.view.MotionEvent import android.view.View import android.widget.EditText import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity class MainActivity : A...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Code

MainActivity.kt

package carleton.comp1601.remotepicview2

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var p: ImageView
    private var pic = R.drawable.kittens

    private lateinit var X: PicParamWatcher
    private lateinit var Y: PicParamWatcher
    private lateinit var scale: PicParamWatcher
    private lateinit var r: PicParamWatcher
    private lateinit var dragV: dragView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState != null) {
            // do something
        }

        p = findViewById(R.id.mypic)
        dragV = dragView(p, ::update, ::toggleImage)

        X = PicParamWatcher(0F, findViewById(R.id.x), ::update)
        Y = PicParamWatcher(0F, findViewById(R.id.y), ::update)
        scale = PicParamWatcher(1F, findViewById(R.id.scale), ::update)
        r = PicParamWatcher(0F, findViewById(R.id.rotation), ::update)

        update()
    }

    fun update() {
        p.setImageResource(pic)
        if (dragV.picDragged) {
            dragV.picDragged = false
            X.value = p.x
            X.refresh()
            Y.value = p.y
            Y.refresh()
        } else {
            p.setX(X.value)
            p.setY(Y.value)
        }
        p.setRotation(r.value)
        p.setScaleX(scale.value)
        p.setScaleY(scale.value)
    }

    fun toggleImage() {
        if (pic == R.drawable.roshi) {
            pic = R.drawable.kittens
        } else {
            pic = R.drawable.roshi
        }
        update()
    }
}

class dragView: View.OnTouchListener {
    var dv: View
    var update: () -> Unit
    var picDragged = false
    var lastWasDown = false
    var clickHandler: () -> Unit

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
        if (event == null || v == null) {
            return false
        }

        val action = event.getAction()

        val x = event.rawX
        val y = event.rawY

        var screenLoc = IntArray(2)
        dv.getLocationOnScreen(screenLoc)
        val Xoffset = screenLoc[0] - dv.x
        val Yoffset = screenLoc[1] - dv.y

        if (action == MotionEvent.ACTION_MOVE) {
            lastWasDown = false
            dv.x = x - (dv.width/2 + Xoffset)
            dv.y = y - (dv.height/2 + Yoffset)
            picDragged = true
            update()
        } else if (action == MotionEvent.ACTION_DOWN) {
            lastWasDown = true
        } else if (action == MotionEvent.ACTION_UP) {
            if (lastWasDown) {
                lastWasDown = false
                clickHandler()
            }
        }

        return true
    }

    constructor(v: View, u: () -> Unit, ch: () -> Unit) {
        dv = v
        dv.setOnTouchListener(this)
        update = u
        clickHandler = ch
    }
}

class PicParamWatcher: TextWatcher {
    var update: () -> Unit
    var widget: EditText
    var defaultValue: Float
    var value: Float
    var valueChanged = false

    override fun afterTextChanged(s: Editable) {
        if (valueChanged) {
            valueChanged = false
            return
        }

        val new_value = s.toString().toFloatOrNull()

        if (new_value != null) {
            value = new_value
        } else {
            value = defaultValue
        }
        update()
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    }

    fun refresh() {
        valueChanged = true
        widget.setText(value.toString())
    }

    constructor(x: Float, w: EditText, u: () -> Unit) {
        update = u
        widget = w
        defaultValue = x
        value = x
        w.addTextChangedListener(this)
        refresh()
    }
}

activity_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/mypic"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginEnd="0dp"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toTopOf="@+id/rotation"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <EditText
        android:id="@+id/rotation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="5"
        android:inputType="number"
        app:layout_constraintBottom_toTopOf="@+id/scale"
        app:layout_constraintStart_toStartOf="@+id/scale" />

    <EditText
        android:id="@+id/scale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="5"
        android:inputType="numberDecimal"
        app:layout_constraintBottom_toTopOf="@+id/x"
        app:layout_constraintStart_toStartOf="@+id/x" />

    <EditText
        android:id="@+id/x"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="5"
        android:inputType="numberSigned"
        app:layout_constraintBottom_toTopOf="@+id/y"
        app:layout_constraintStart_toStartOf="@+id/y" />

    <EditText
        android:id="@+id/y"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="32dp"
        android:ems="5"
        android:inputType="numberSigned"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/ylabel" />

    <TextView
        android:id="@+id/rotationlabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:text="rotation"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/rotation"
        app:layout_constraintEnd_toStartOf="@+id/rotation"
        />

    <TextView
        android:id="@+id/scalelabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_marginBottom="11dp"
        android:text="scale"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/scale"
        app:layout_constraintEnd_toStartOf="@+id/scale" />

    <TextView
        android:id="@+id/xlabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:text="X"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/x"
        app:layout_constraintEnd_toStartOf="@+id/x" />

    <TextView
        android:id="@+id/ylabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:text="Y"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@+id/y"
        app:layout_constraintEnd_toStartOf="@+id/y" />

</androidx.constraintlayout.widget.ConstraintLayout>