Monday, November 2, 2020

Android exercise: ImageFilterView (Kotlin)

ImageFilterView is a An ImageView that can display, combine and filter images, to handle various common filtering operations. You can set saturation, contrast, warmth and some othters (refer to the document) in layout XML, or change it at run-time.

ImageFilterView was added in ConstraintLayout 2.0, so make sure dependencies of implementation 'androidx.constraintlayout:constraintlayout:2.0.0' or higher is include in your build.grade(Module:) file.


build.grade(Module:)
dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
}
Layout 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"
    android:layout_margin="20dp"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toTopOf="@id/imagefilterview"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="ImageFilterView Example (Kotlin)"
            android:textStyle="bold" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Android-er.blogspot.com" />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:mipmap/sym_def_app_icon"/>

    </LinearLayout>

    <androidx.constraintlayout.utils.widget.ImageFilterView
        android:id="@+id/imagefilterview"
        android:src="@android:mipmap/sym_def_app_icon"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/panel"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/header"
        app:saturation="1.0"
        app:contrast="1.0"
        app:brightness="1.0"/>

    <LinearLayout
        android:id="@+id/panel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/imagefilterview">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Saturation"/>
        <TextView
            android:id="@+id/sat"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarSat"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Contrast"/>
        <TextView
            android:id="@+id/cont"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarCont"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Warmth"/>
        <TextView
            android:id="@+id/warm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarWarm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
Kotlin code:
package com.blogspot.android_er.eximgfilterview2

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.SeekBar
import android.widget.TextView
import androidx.constraintlayout.utils.widget.ImageFilterView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val MyImageFilterView =
                findViewById<ImageFilterView>(R.id.imagefilterview)

        val MySeekBarSat = findViewById<SeekBar>(R.id.seekBarSat)
        val MyTextViewSat = findViewById<TextView>(R.id.sat)
        val MySeekBarCont = findViewById<SeekBar>(R.id.seekBarCont)
        val MyTextViewCont = findViewById<TextView>(R.id.cont)
        val MySeekBarWarm = findViewById<SeekBar>(R.id.seekBarWarm)
        val MyTextViewWarm = findViewById<TextView>(R.id.warm)

        //Get the first-run setting of saturation, contrast and warmth
        MyTextViewSat.text= MyImageFilterView.saturation.toString()
        MyTextViewCont.text= MyImageFilterView.contrast.toString()
        MyTextViewWarm.text= MyImageFilterView.warmth.toString()

        MySeekBarSat.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                //update saturation
                MyImageFilterView.saturation = (progress / 100.0f) * 2
                //read back the saturation
                MyTextViewSat.text= MyImageFilterView.saturation.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        MySeekBarCont.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                MyImageFilterView.contrast = (progress / 100.0f) * 2
                MyTextViewCont.text= MyImageFilterView.contrast.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        MySeekBarWarm.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                MyImageFilterView.warmth = (progress / 100.0f) * 2
                MyTextViewWarm.text= MyImageFilterView.warmth.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })
    }
}



Then add the feature to change Crossfade, also show how overlay setting affect the crossfade result.


Layout 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"
    android:layout_margin="20dp"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toTopOf="@id/imagefilterview"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="ImageFilterView Example (Kotlin)"
            android:textStyle="bold" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Android-er.blogspot.com" />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:mipmap/sym_def_app_icon"/>

    </LinearLayout>

    <androidx.constraintlayout.utils.widget.ImageFilterView
        android:id="@+id/imagefilterview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/panel"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/header"

        android:src="@android:mipmap/sym_def_app_icon"
        app:altSrc="@android:drawable/btn_star_big_on"
        app:overlay="false"
        app:crossfade="0.0"
        app:saturation="1.0"
        app:contrast="1.0"
        app:warmth="1.0"
         />

    <LinearLayout
        android:id="@+id/panel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/imagefilterview">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Crossfade"/>
        <TextView
            android:id="@+id/crossfade"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarCrossfade"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="0"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Saturation"/>
        <TextView
            android:id="@+id/sat"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarSat"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Contrast"/>
        <TextView
            android:id="@+id/cont"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarCont"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Warmth"/>
        <TextView
            android:id="@+id/warm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <SeekBar
            android:id="@+id/seekBarWarm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="50"/>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Kotlin code:

package com.blogspot.android_er.eximgfilterview2

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.SeekBar
import android.widget.TextView
import androidx.constraintlayout.utils.widget.ImageFilterView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val MyImageFilterView =
                findViewById<ImageFilterView>(R.id.imagefilterview)

        val MySeekBarCrossfade = findViewById<SeekBar>(R.id.seekBarCrossfade)
        val MyTextViewCrossfade = findViewById<TextView>(R.id.crossfade)

        val MySeekBarSat = findViewById<SeekBar>(R.id.seekBarSat)
        val MyTextViewSat = findViewById<TextView>(R.id.sat)
        val MySeekBarCont = findViewById<SeekBar>(R.id.seekBarCont)
        val MyTextViewCont = findViewById<TextView>(R.id.cont)
        val MySeekBarWarm = findViewById<SeekBar>(R.id.seekBarWarm)
        val MyTextViewWarm = findViewById<TextView>(R.id.warm)

        //Get the first-run setting of crossfade, saturation, contrast and warmth
        MyTextViewCrossfade.text= MyImageFilterView.crossfade.toString()
        MyTextViewSat.text= MyImageFilterView.saturation.toString()
        MyTextViewCont.text= MyImageFilterView.contrast.toString()
        MyTextViewWarm.text= MyImageFilterView.warmth.toString()

        MySeekBarCrossfade.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
                    override fun onProgressChanged(seekBar: SeekBar?,
                                                   progress: Int, fromUser: Boolean) {
                        //update saturation
                        MyImageFilterView.crossfade = (progress / 100.0f)
                        //read back the saturation
                        MyTextViewCrossfade.text= MyImageFilterView.crossfade.toString()
                    }

                    override fun onStartTrackingTouch(seekBar: SeekBar?) {}

                    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
                })

        MySeekBarSat.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                //update saturation
                MyImageFilterView.saturation = (progress / 100.0f) * 2
                //read back the saturation
                MyTextViewSat.text= MyImageFilterView.saturation.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        MySeekBarCont.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                MyImageFilterView.contrast = (progress / 100.0f) * 2
                MyTextViewCont.text= MyImageFilterView.contrast.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        MySeekBarWarm.setOnSeekBarChangeListener(
                object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?,
                                           progress: Int, fromUser: Boolean) {
                MyImageFilterView.warmth = (progress / 100.0f) * 2
                MyTextViewWarm.text= MyImageFilterView.warmth.toString()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })
    }
}

No comments: