how to get data from dynamically created views - android

I am pretty much a beginner in app development. I am creating a GPA calculator. I was able to create a button that would create a new EditText view for each time it was tapped. but I don't know how can get the values from those EditTexts separately so I can use them to calculate GPA. I looked up every similar question here and on the internet in general, but none of them helped me. Here is my code:
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">
<LinearLayout
android:id="#+id/layout_list"
android:layout_width="match_parent"
android:layout_height="500dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="#+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:drawableRight="#drawable/ic_baseline_add_24"
android:text="Add"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
</LinearLayout>
<Button
android:id="#+id/calculate_button"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="Calculate"
app:layout_constraintLeft_toLeftOf="#id/layout_list"
app:layout_constraintTop_toBottomOf="#id/layout_list" />
<TextView
android:id="#+id/result"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="13dp"
android:hint="GPA:0.0"
android:textSize="20dp"
app:layout_constraintStart_toEndOf="#id/calculate_button"
app:layout_constraintTop_toBottomOf="#id/layout_list"
tools:text="GPA:0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
new_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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/gpa_points"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#drawable/custom_input"
android:hint=" GPA point"
android:inputType="number"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/credit_points"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#drawable/custom_input"
android:hint=" ETCS"
android:inputType="number"
app:layout_constraintStart_toEndOf="#+id/gpa_points"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="18dp"
android:background="#drawable/ic_baseline_close_24"
app:layout_constraintLeft_toRightOf="#id/credit_points"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
package com.example.gpacalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
class MainActivity : AppCompatActivity() {
private var layout: LinearLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
layout = findViewById(R.id.layout_list)
val addButton: Button = findViewById(R.id.add_button)
addButton.setOnClickListener { addView() }
val calculateButton: Button = findViewById(R.id.calculate_button)
calculateButton.setOnClickListener { calculate() }
}
private fun addView() {
val gpaView: View = layoutInflater.inflate(R.layout.new_layout, null, false)
layout?.addView(gpaView)
}
i added this function to my code
fun calculate(){
var total = 0.0
var etcs = 0.0
layout.children.forEach { newLayout ->
// Find the gpa_points EditText in the child layout
val gpaPointsEditText = newLayout.findViewById<EditText>(R.id.gpa_points) as? EditText
val creditsEditText = newLayout.findViewById<EditText>(R.id.credit_points) as? EditText
// Parse the text to be able to perform calculations
val gpaPoints = gpaPointsEditText?.text.toString().toDouble()
val credits = creditsEditText?.text.toString().toDouble()
total+=gpaPoints*credits
etcs+=credits
}
var gpa = total/etcs
val result:TextView = findViewById(R.id.result)
result.text=gpa.toString()
}
but it gives me an error like this
java.lang.NumberFormatException: For input string: "null"
atsun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at com.example.gpacalculator.MainActivity.calculate(MainActivity.kt:46)
at com.example.gpacalculator.MainActivity.onCreate$lambda1(MainActivity.kt:27)
at com.example.gpacalculator.MainActivity.$r8$lambda$1xRU0rpJNKxzUpdKrPz49s5lowk(Unknown Source:0)
at com.example.gpacalculator.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:2)

You can iterate on the child views of layout, and retrieve the GPA.
// Get a decimal format for the current locale
private val decimalFormat = DecimalFormat.getInstance()
// Iterate on the children of layout
layout.children.forEach { newLayout ->
// Find the gpa_points EditText in the child layout
val gpaPointsEditText = newLayout.findViewById<EditText>(R.id.gpa_points) as EditText
// Parse the text to be able to perform calculations
val gpaPointsStr = gpaPointsEditText.text.toString()
val gpaPoints = decimalFormat.parse(str)
}
To learn more about layouts :
https://developer.android.com/guide/topics/ui/declaring-layout

Related

Duplicate and overlapping text in TextView when using LiveData or StateFlow

To be as clear as possible, I'm going to show the problem with a gif.
As you can see, the text is overlapping in my emulator and I don't know how to solve it, I don't know what I'm doing wrong.
It should be displayed correctly without overlapping. What I'm doing is subscribing to changes in both LiveData and StateFlow. When I press the button, I make it change the value, but instead of changing, it seems to return both values at once (Default and Hello). Could it be that the view is not refreshing? Or could it be a problem with my emulator?
Anyway, I'll leave all the code here in case you can figure it out.
FlowsFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.rr.stateflow_livedata_flow_sharedflow.databinding.FragmentFlowsBinding
import kotlinx.coroutines.flow.collectLatest
class FlowsFragment : Fragment(R.layout.fragment_flows) {
private lateinit var binding: FragmentFlowsBinding
private val viewModel: FlowsViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentFlowsBinding.bind(view)
binding.btnLiveData.setOnClickListener {
viewModel.triggerLiveData()
}
binding.btnStateFlow.setOnClickListener {
viewModel.triggerStateFlow()
}
subscribeToObservables()
}
private fun subscribeToObservables() {
viewModel.liveData.observe(viewLifecycleOwner) {
binding.tvLiveData.text = it
}
lifecycleScope.launchWhenStarted {
viewModel.stateFlow.collectLatest {
binding.tvStateFlow.text = it
}
}
}
}
FlowsViewModel.kt
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.*
class FlowsViewModel : ViewModel() {
private val _liveData = MutableLiveData("Default LiveData")
val liveData: LiveData<String> = _liveData
private val _stateFlow = MutableStateFlow("Default StateFlow")
val stateFlow: StateFlow<String> = _stateFlow.asStateFlow()
fun triggerLiveData() {
_liveData.value = "Hello LiveData!"
}
fun triggerStateFlow() {
_stateFlow.value = "Hello StateFlow!"
}
}
fragment_flows.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=".FlowsFragment">
<TextView
android:id="#+id/tvLiveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnLiveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="LIVEDATA"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvLiveData" />
<TextView
android:id="#+id/tvStateFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnLiveData" />
<Button
android:id="#+id/btnStateFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="STATEFLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvStateFlow" />
<TextView
android:id="#+id/tvFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnStateFlow" />
<Button
android:id="#+id/btnFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="FLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvFlow" />
<TextView
android:id="#+id/tvSharedFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnFlow" />
<Button
android:id="#+id/btnSharedFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="SHAREDFLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSharedFlow" />
</androidx.constraintlayout.widget.ConstraintLayout>
I hope that the text doesn't overlap and returns the latest value of LiveData and StateFlow.
Edit with more info: The application displays the view directly from the fragment, MainActivity only has a fragment container that I show below.
MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.add
import androidx.fragment.app.commit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportFragmentManager.commit {
setReorderingAllowed(true)
add<FlowsFragment>(R.id.mainActivityFragmentContainer)
}
}
}
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">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/mainActivityFragmentContainer"
android:name="com.rr.stateflow_livedata_flow_sharedflow.FlowsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/fragment_flows" />
</androidx.constraintlayout.widget.ConstraintLayout>
EDIT This is not the solution, it's a bad way to solve the problem.
I just have to add this line of code in fragment_flows.xml.
android:background="#color/white"
Just by setting the background of the fragment to white, the text is no longer duplicated and overlapping.
Does anyone know why this happens? Why does what is drawn on the screen stick to the background if there is no background in the fragment layout?

Perform an if-else statement in Android, and the application crashes on button click

I am currently working on a currency converter in Android Studio. The error that I faced was that if I were to put the current input, which is "US Dollars" in the editTextCurrency box (enter currency box) and click on the convert button, the application would crash. However, if I were to put a wrong input for example "US" in the editTextCurrency(Enter currency box), the application did not crash but print out the message on the TextView which is intended to. I am not sure how I should solve this issue, I hope someone could point out the error that I made. Thanks.
kt file
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import edu.singaporetech.travelapp.databinding.ActivityCurrencyConverterBinding
/**
* Activity that displays UI to convert currency
*/
class CurrencyConverterActivity : AppCompatActivity() {
private lateinit var binding: ActivityCurrencyConverterBinding
val TAG: String = "CurrencyConverterActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCurrencyConverterBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.editTextCurrency
binding.editTextRate
binding.editTextSingDollar
binding.currencyTextView
binding.rateTextView
binding.singdollarTextView
binding.convertCurrencyButton
binding.currencyOutputTextView
binding.convertCurrencyButton.setOnClickListener {
if (binding.editTextCurrency.text.toString() == "US Dollars"){
binding.currencyOutputTextView.visibility = View.VISIBLE
var currencyResult = calculateRate(binding.editTextSingDollar.toString().toFloat(), binding.editTextRate.toString().toFloat())
binding.currencyOutputTextView.text = getString(R.string.display_currency, binding.editTextSingDollar.toString().toFloat(), currencyResult)
}else{
binding.currencyOutputTextView.text = getString(R.string.invalid_currency)
binding.currencyOutputTextView.visibility = View.VISIBLE
}
}
}
}
private fun calculateRate(value: Float, exchangeRate: Float): Float {
// TODO What's the formula you need?
return value * exchangeRate
}
xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/currencyTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/currency"
android:textSize="24sp" />
<EditText
android:id="#+id/editTextCurrency"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/input_currency"
android:inputType="textPersonName"
android:textSize="20sp" />
<TextView
android:id="#+id/rateTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/rate"
android:textSize="24sp" />
<EditText
android:id="#+id/editTextRate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/input_rate"
android:inputType="numberDecimal"
android:minHeight="48dp"
android:textSize="20sp" />
<TextView
android:id="#+id/singdollarTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/singapore_dollars"
android:textSize="24sp" />
<EditText
android:id="#+id/editTextSingDollar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/input_singapore_dollars"
android:inputType="numberDecimal"
android:textSize="20sp" />
<Button
android:id="#+id/convertCurrencyButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/convert" />
<TextView
android:id="#+id/currencyOutputTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAlignment="center"
android:visibility="invisible" />
</LinearLayout>
string.xml
<resources>
<string name="invalid_currency">Invalid Currency</string>
<string name="display_currency">%.1f SGD is %.1f Singapore Dollars</string>
</resources>
Changes
binding.convertCurrencyButton.setOnClickListener {
if (binding.editTextCurrency.text.toString() == "US Dollars"){
binding.currencyOutputTextView.visibility = View.VISIBLE
var currencyResult = calculateRate(binding.editTextSingDollar.text.toString().toFloat(), binding.editTextRate.text.toString().toFloat())
binding.currencyOutputTextView.text = getString(R.string.display_currency, binding.editTextSingDollar.text.toString().toFloat(), currencyResult)
}else{
binding.currencyOutputTextView.text = getString(R.string.invalid_currency)
binding.currencyOutputTextView.visibility = View.VISIBLE
}
}
Error message that I got from logcat
java.lang.NumberFormatException: For input string: "androidx.appcompat.widget.AppCompatEditText

How to implement a SearchView to search specific buttons in a LinearLayout?

I'm opening this discussion because I need help for a school project.
At the moment, I have a scrollable activity with some buttons, everything is built like this:
a constraint layout, with SearchView, ScrollView and a BottomNavigationBar, and inside the ScrollView there's a LinearLayout with all my buttons.
Here is the full xml file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<SearchView
android:id="#+id/BarraRicerca"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:gravity="top"
android:iconifiedByDefault="false"
android:imeOptions="actionDone"
android:queryHint="Cerca un tutorial"
android:labelFor="#id/BarraRicerca"
android:suggestionRowLayout="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:id="#+id/scrollView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:fillViewport="false"
android:orientation="vertical"
android:padding="10dp"
android:layout_marginTop="60dp"
app:layout_constraintBottom_toTopOf="#id/BottomBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/BarraRicerca">
<LinearLayout
android:id="#+id/Linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.Flipper.FlipperList">
<Button
android:id="#+id/FlintstonesF"
android:layout_width="300dp"
android:layout_height="49dp"
android:layout_gravity="center_horizontal"
android:layout_margin="100dp"
android:text="Flintstones" />
<Button
android:id="#+id/tutorial2"
android:layout_width="300dp"
android:layout_height="49dp"
android:layout_gravity="center_horizontal"
android:layout_margin="200dp"
android:layout_weight="1"
android:text="ciao" />
<Button
android:id="#+id/tutorial3"
android:layout_width="300dp"
android:layout_height="49dp"
android:layout_gravity="center_horizontal"
android:layout_margin="100dp"
android:layout_weight="1"
android:text="hello" />
</LinearLayout>
</ScrollView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/BottomBar"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
and the result is this, everything works
Now I need to implement the SearchView to actually search through my buttons, For example if I search Flintstones (or Flint, or Fli etc.) I want the Flintstones button to be the only one shown. The same goes for "ciao" and so on, I will obviously have more buttons than these.
I tried every possible solution I found on the internet but nothing seems to work. This is my code
package com.example.Flipper
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.example.pinballacademy.R
class FlipperList : AppCompatActivity() {
val passaFlintstones: Button get() = findViewById(R.id.FlintstonesF)
val bottone2: Button get() = findViewById(R.id.tutorial2)
val bottone3: Button get() = findViewById(R.id.tutorial3)
val searchbar: SearchView get() = findViewById(R.id.BarraRicerca)
val linLay: LinearLayout get() = findViewById(R.id.Linearlayout)
var listaFlipper: ArrayList<String> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flipper_list)
/* listaFlipper.clear();
listaFlipper.add(passaFlintstones.text.toString())
listaFlipper.add(bottone2.text.toString())
listaFlipper.add(bottone3.text.toString())*/
searchbar.isSubmitButtonEnabled=true
searchbar.setOnQueryTextListener() {
fun onQueryTextChange(newText: String?): Boolean {
filter(newText)
return true
}
fun onQueryTextSubmit(query: String?): Boolean {
filter(query)
return true
}
// Do your task here
}
passaFlintstones.setOnClickListener()
{
val intent = Intent(this, FlintstonesScheda::class.java)
//avvia registrazione
startActivity(intent)
// finish()
}
}
fun filter(searchText: String?) {
for (i in 0 until linLay.childCount) {
val button: Button = linLay.getChildAt(i) as Button
if (button.text.toString().contains(searchText!!)) {
button.isVisible=true
} else button.isVisible=false
}
}
private fun SearchView.setOnQueryTextListener(function: () -> Unit) {
}
}
As you can see I'm not even near to a solution, I hope you can help! Thank you!

How to save a screen as an image in the mobile device. I am using kotlin to make a meme creator app for android

I am making a meme creator app. I will load memes from firebase database and the user will select one of the meme templates and will start editting it. For entering text in the memes i am using the github library implementation 'com.github.hantrungkien:Awesome-Input-Layout:1.0.0'
It allows the user to rotate the textview, move it with finger and all. But the problem is i am very new to android dev. I dont know how to save the background meme image plus the text entered by user in the user's device or gallery. Please tell me detailed steps as i am pretty new. Every help is appreciated.
My Meme editting activity code
package com.example.memecreator
import android.app.Activity
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.RelativeLayout
import com.squareup.picasso.Picasso
import htkien.awesome_input.AwesomeInputLayout
import kotlinx.android.synthetic.main.activity_meme.*
class MemeActivity : AppCompatActivity() {
val TAG = MainActivity::class.java.simpleName
var mLayoutRoot: RelativeLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meme)
setSupportActionBar(meme_toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
meme_toolbar.setNavigationOnClickListener {
finish()
}
//I am passing intent from last activity and using picasso to load images. Its working fine.
val intent=intent
val memeImage=intent.getStringExtra("image")
Picasso.get().load(memeImage).into(meme_image)
mLayoutRoot=findViewById<RelativeLayout>(R.id.rl_meme)
val added=findViewById<Button>(R.id.btn_add_text)
added.setOnClickListener {
onClickBtnAddText()
}
}
override fun onBackPressed() {
if (!mLayoutRoot!!.isFocused) {
mLayoutRoot!!.requestFocus()
mLayoutRoot!!.requestFocusFromTouch()
} else {
super.onBackPressed()
}
}
private fun onClickBtnAddText() {
val awesomeLayout = LayoutInflater.from(this).inflate(
R.layout.layout_awesome_input,
mLayoutRoot,
false
) as AwesomeInputLayout
mLayoutRoot?.addView(awesomeLayout)
awesomeLayout.post {
val w = mLayoutRoot!!.width
val h = mLayoutRoot!!.height
awesomeLayout.x = w / 2 - awesomeLayout.width / 2.toFloat()
awesomeLayout.y = h / 2 - awesomeLayout.height / 2.toFloat()
awesomeLayout.requestLayout()
awesomeLayout.visibility = View.VISIBLE
showKeyboard(this#MemeActivity)
}
awesomeLayout.setDeleteViewListener { awesomeLayout ->
hideKeyboard(awesomeLayout)
mLayoutRoot!!.requestFocus()
mLayoutRoot!!.requestFocusFromTouch()
try {
mLayoutRoot!!.removeView(awesomeLayout)
} catch (e: IndexOutOfBoundsException) {
Log.e(TAG, "onDeleteView: ", e)
}
}
}
private fun hideKeyboard(view: View) {
val imm =
view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(
InputMethodManager.HIDE_IMPLICIT_ONLY,
0
) // hide
}
private fun showKeyboard(activity: Activity) {
val imm = activity.getSystemService(
Activity.INPUT_METHOD_SERVICE
) as InputMethodManager
imm.toggleSoftInput(
0,
InputMethodManager.HIDE_IMPLICIT_ONLY
) // show
}
}
My Meme editting xml code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl_meme"
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=".MemeActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout_meme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:background="#android:color/white">
<androidx.appcompat.widget.Toolbar
android:id="#+id/meme_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/colorDarkGrey">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Meme"
android:textSize="20sp"
android:maxLines="1"
android:textStyle="bold"
android:textColor="#android:color/white"
android:layout_centerVertical="true"/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/meme_image"
android:layout_width="match_parent"
android:layout_height="420dp"
android:layout_marginTop="152dp"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_add_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/meme_image"
android:text="Add Text"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/meme_image" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
and finally the design of the edittext which i used from the github library
<?xml version="1.0" encoding="utf-8"?>
<htkien.awesome_input.AwesomeInputLayout
xmlns:autofit="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginTop="152dp"
android:background="#drawable/button_black_background"
android:orientation="vertical"
android:visibility="invisible">
<ImageButton
android:id="#+id/button_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#android:color/transparent"
android:scaleType="fitXY"
android:src="#drawable/ic_cross" />
<EditText
android:id="#+id/edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="10dp"
android:hint="Type"
android:imeOptions="flagNoExtractUi"
android:textColor="#color/colorDark"
android:textColorHint="#color/colorDark"
android:textSize="16sp" />
</htkien.awesome_input.AwesomeInputLayout>
This is a screenshot image of my edit meme activity screen. I want to save this in the device
Let's modify the ConstraintLayout inside activity_meme layout a little bit,
...
...
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/meme_container"
android:layout_width="match_parent"
android:layout_height="420dp"
android:layout_marginTop="152dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/meme_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</FrameLayout>
<Button
android:id="#+id/btn_add_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/meme_container"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:text="Add Text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/meme_container" />
</androidx.constraintlayout.widget.ConstraintLayout>
...
...
Inside onCreate, replace
mLayoutRoot = findViewById<RelativeLayout>(R.id.rl_meme)
with
mLayoutRoot = findViewById<FrameLayout>(R.id.meme_container)
This layout will now contain the meme image with text. Hence we call drawToBitmap on mLayoutRoot and save the image.

how do i save / use user input in android kotlin

i'm trying to write my very first android app. the only programing i have done in the past was some html 4 many years ago (before cms was a thing)
it is essentially a check list but i want to be able to have multiple lists seperated by a list name supplied by the user. i have an input text box called "island name" but i cant figure out how to capture that text from the user and save it for future use...
<?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">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="189dp"
android:text="temp call islander page"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="125dp"
android:layout_marginBottom="271dp"
android:onClick="loadHome"
android:text="home"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="41dp"
android:ems="10"
android:hint="island name"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/button" />
<CheckBox
android:id="#+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="7dp"
android:layout_marginBottom="8dp"
android:text="north"
app:layout_constraintBottom_toTopOf="#+id/checkBox2"
app:layout_constraintEnd_toEndOf="#+id/checkBox2" />
<CheckBox
android:id="#+id/checkBox2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginBottom="88dp"
android:text="south"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="#+id/editText" />
println("your island name is $name")
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="19dp"
android:text="you entered $name"
app:layout_constraintStart_toEndOf="#+id/checkBox2"
app:layout_constraintTop_toBottomOf="#+id/checkBox2" />
</androidx.constraintlayout.widget.ConstraintLayout>
To put it simply, in Android dev (Android Studio) you have your view, which is your .xml file and your program logic is written in your .kt or .java file then you refer to your respective view from the .kt oe ,java file.
e.g
activity_main.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/textView"
android:layout_height="wrap_content"
android:layout_width="200dp"/>
<Button
android:id="#+id/saveBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save" />
</LinearLayout>
MainActivity.kt :
import kotlinx.android.synthetic.main.activity_main.* //this will reference all views in activity_main -
//Android studio usually auto imports this when you simply type control name
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
saveBtn.setOnClickListener {
saveDetails()
}
}
fun saveDetails(){
var userText = textView.text.toString()
textView4.setText(userText)
//do something with text
}
}
For those who is experiencing the same issue you can use sharedPreferences. As an example:
private lateinit var sp: SharedPreferences
private lateinit var editor: SharedPreferences.Editor
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
nameEditText = findViewById(R.id.etName)
ageEditText = findViewById(R.id.etAge)
sp = getSharedPreferences("my_sf", MODE_PRIVATE)
editor = sp.edit()
}
override fun onPause() {
super.onPause()
val name = nameEditText.text.toString()
val age = ageEditText.text.toString().toInt()
editor.apply {
putString("my_name", name)
putInt("my_age", age)
commit()
}
}
override fun onResume() {
super.onResume()
val name = sp.getString("my_name", null)
val age = sp.getInt("my_age", 0)
nameEditText.setText(name)
if (age!=0) ageEditText.setText(age.toString())
}

Categories

Resources