I'm trying to change the style of my AutocompleteSupportFragment field
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/llSearchHolder"
android:padding="7dp">
<fragment android:id="#+id/autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:hint="#string/Iam_going_to"
/>
</LinearLayout>
I tried implementing answers on this page but I will always get Caused by: java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.EditText error. I'm using Kotlin, so my code looks like below:
val autocompleteFragment = supportFragmentManager.findFragmentById(R.id.autocomplete_fragment) as AutocompleteSupportFragment?
autocompleteFragment!!.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME));
((autocompleteFragment.getView()!!.findViewById(R.id.autocomplete_fragment)) as EditText).textSize = 30.0f
You need to use below code
((autocompleteFragment.getView()!!.findViewById(R.id.places_autocomplete_search_input)) as EditText).textSize = 30.0f
or more Kotlin way,
autocompleteFragment.view?.findViewById<EditText>(R.id.places_autocomplete_search_input)?.textSize = 30.0f
The correct id of EditText is places_autocomplete_search_input not autocomplete_fragment
Analysis of the problem
You are using Fragment com.google.android.libraries.places.widget.AutocompleteSupportFragment in your xml
While looking into the code of AutocompleteSupportFragment Fragment, you can see it uses layout places_autocomplete_fragment.xml. Code below
public class AutocompleteSupportFragment extends Fragment {
....
public AutocompleteSupportFragment() {
super(layout.places_autocomplete_fragment);
....
}
}
Now, if you look into places_autocomplete_fragment.xml, you can see id of EditText is places_autocomplete_search_input, code below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:layoutDirection="locale"
android:orientation="vertical"
android:textDirection="locale">
<ImageButton
android:id="#+id/places_autocomplete_search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:background="#null"
android:contentDescription="#string/places_autocomplete_search_hint"
android:padding="#dimen/places_autocomplete_button_padding"
android:src="#drawable/quantum_ic_search_grey600_24" />
<EditText
android:id="#+id/places_autocomplete_search_input"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#null"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="#string/places_autocomplete_search_hint"
android:inputType="textNoSuggestions"
android:lines="1"
android:maxLines="1"
android:paddingLeft="#dimen/places_autocomplete_search_input_padding"
android:paddingRight="#dimen/places_autocomplete_search_input_padding"
android:singleLine="true"
android:textColor="#color/places_autocomplete_search_text"
android:textColorHint="#color/places_autocomplete_search_hint"
android:textSize="#dimen/places_autocomplete_search_input_text" />
<ImageButton
android:id="#+id/places_autocomplete_clear_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:background="#null"
android:contentDescription="#string/places_autocomplete_clear_button"
android:padding="#dimen/places_autocomplete_button_padding"
android:src="#drawable/quantum_ic_clear_grey600_24" />
</LinearLayout>
Android might suggest to Replace the <fragment> tag with FragmentContainerView. in your xml file. That breaks custom styling, so keep using <fragment>:
Use this:
<fragment
android:id="#+id/hostAutocompleteFrag"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Don't use this:
<androidx.fragment.app.FragmentContainerView
android:id="#+id/hostAutocompleteFrag"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here's my AutocompleteSupportFragment init method for your reference:
private fun initAutoComplete() {
val mapAutocomplete = childFragmentManager.findFragmentById(R.id.hostAutocompleteFrag)
autoCompFrag = mapAutocomplete as AutocompleteSupportFragment
val hintTxt = autoCompFrag?.findViewById<EditText>(R.id.places_autocomplete_search_input)
hintTxt?.textSize = 15f
hintTxt?.setTextColor(requireContext().getColor(R.color.greyColor))
autoCompFrag.setHint(getString(R.string.search_hint))
autoCompFrag.setPlaceFields(listOf(Place.Field.NAME, Place.Field.LAT_LNG, Place.Field.ADDRESS))
autoCompFrag.setOnPlaceSelectedListener(object : PlaceSelectionListener {
override fun onPlaceSelected(place: Place) {
val latLng = place.latLng ?: return
setMapLocation(latLng.latitude, latLng.longitude)
}
override fun onError(status: Status) {
Log.e("$TAG initAutoComplete --- ", "An error occurred: $status")
}
})
}
For changing the EditText color in kotlin
val autocompleteFragment = supportFragmentManager.findFragmentById(R.id.autocompleteFragment) as AutocompleteSupportFragment?
autocompleteFragment.view?.findViewById<EditText>(places_autocomplete_search_input)?.setTextColor(ContextCompat.getColor(context, R.color.colorWhite));
if still not able to change then try to set the color in values as
<color name="places_autocomplete_search_text">#707070</color>
the key is important places_autocomplete_search_text
Related
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
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
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.
Using a spinner on a fragment, all seems to be good, but when I add an EditText and set focus in EditText, my spinner listener won't respond...
I have tried a lot of things, like change my spinner data, delete all the disruptive code, change layouts.
<FrameLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:background="#drawable/button_orange"
android:layout_marginBottom="10dp" android:layout_marginTop="10dp">
<androidx.appcompat.widget.AppCompatSpinner
android:layout_width="wrap_content"
android:layout_height="match_parent" android:id="#+id/spinnerCountries"
android:spinnerMode="dropdown" android:layout_margin="5dp"/>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#color/white"/>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/input_layout_phone"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#color/orange">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/input_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone"
android:hint="#string/hint_phone_number"
android:importantForAutofill="noExcludeDescendants"
android:maxLength="20"
android:drawableRight="#mipmap/icon_help_phone"
android:textColor="#color/orange"
tools:ignore="UnusedAttribute" android:background="#null" android:fitsSystemWindows="true"/>
</com.google.android.material.textfield.TextInputLayout>
</FrameLayout>
mSpinnerCountries!!.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(arg0: AdapterView<*>, arg1: View, position: Int, arg3: Long) {
prefs!!["country_position"] = position
val mSelectedCountry = arg0.selectedItem as Pays?
prefs!!["user_countrycode"] = mSelectedCountry?.code
prefs!!["carrier_countryiso"] = mSelectedCountry?.iso
prefs!!["country_prefix"] = mSelectedCountry?.prefix
Timber.d("Item selected on spinner : code ${mSelectedCountry?.code}, iso ${mSelectedCountry?.iso}, prefix ${mSelectedCountry?.prefix}")
mEditText!!.text!!.clear()
mEditText!!.text!!.clearSpans()
mEditText!!.setText(mSelectedCountry?.prefix)
mEditText!!.setSelection(mSelectedCountry?.prefix!!.length)
}
override fun onNothingSelected(arg0: AdapterView<*>) {
val mSelectedCountry = arg0.selectedItem as Pays?
prefs!!["user_countrycode"] = mSelectedCountry?.code
prefs!!["carrier_countryiso"] = mSelectedCountry?.iso
prefs!!["country_prefix"] = mSelectedCountry?.prefix
Timber.d("No Item selected on spinner : code ${mSelectedCountry?.code}, iso ${mSelectedCountry?.iso}, prefix ${mSelectedCountry?.prefix}")
mEditText!!.setText(mSelectedCountry?.prefix)
mEditText!!.setSelection(mSelectedCountry?.prefix!!.length+1)
}
}
Now I expect to be able to use the spinner listener even after the edited text has been focused.
The code you've posted works as expected.
Can you please create a very simple project and add this line to that project and check if everything works properly? If below code works in your simple project we can debug your main project further. If this is not working, then there could be a problem in your device.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:background="#mipmap/ic_launcher"
android:layout_marginBottom="10dp" android:layout_marginTop="10dp">
<androidx.appcompat.widget.AppCompatSpinner
android:layout_width="wrap_content"
android:layout_height="match_parent" android:id="#+id/spinnerCountries"
android:spinnerMode="dropdown" android:layout_margin="5dp"/>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#android:color/white"/>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/input_layout_phone"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#android:color/holo_orange_dark">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/input_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone"
android:hint="phone number"
android:importantForAutofill="noExcludeDescendants"
android:maxLength="20"
android:drawableRight="#mipmap/ic_launcher"
android:textColor="#android:color/holo_orange_dark"
tools:ignore="UnusedAttribute" android:background="#null" android:fitsSystemWindows="true"/>
</com.google.android.material.textfield.TextInputLayout>
</FrameLayout>
</LinearLayout>
MainActivity.kt
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, Arrays.asList("a","b","c"))
spinnerCountries.adapter =adapter
spinnerCountries!!.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(arg0: AdapterView<*>, arg1: View, position: Int, arg3: Long) {
input_phone!!.text!!.clear()
input_phone!!.text!!.clearSpans()
input_phone!!.setText(adapter.getItem(position))
input_phone!!.setSelection(adapter?.getItem(position)!!.length)
}
override fun onNothingSelected(arg0: AdapterView<*>) {
}
}
}
}
I'm looking for a way to recreate the alert dialog in the Setting application of Android Wear:
Which is swipe to dismissable.
But instead, what I got is this:
Just a barebone Android dialog. How can I show the AlertDialog in the Settings.apk style? (Which I think must be default for Android Wear application)
I found no default way to do this, also setting a custom view to an AlertDialog did not look good. You can still try though, maybe a different Theme works.
What I did was create a new Activity and create my own layout which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
app:layout_box="all">
<TextView
android:id="#+id/tv_longtext"
android:layout_width="match_parent"
android:layout_height="0sp"
android:layout_weight="1"
android:fontFamily="sans-serif-condensed"
android:gravity="bottom"
android:padding="5sp"
android:text="Ambient screen reduces battery life."
android:textSize="16sp" />
<TextView
android:id="#+id/tv_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal|top"
android:paddingBottom="15sp"
android:paddingTop="5sp"
android:text="Turn on?"
android:textSize="18sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5sp">
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|bottom"
android:src="#drawable/ic_cross"
app:circle_color="#AFAFAF"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:src="#drawable/ic_tick"
app:circle_color="#0EB695"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
</FrameLayout>
</LinearLayout>
</android.support.wearable.view.BoxInsetLayout>
It looks just like the confirmation screen from the settings. Maybe it still needs some tweaks, but I think this is the way to go.
I had a similar problem and indeed I didn't find a default way to do this. I tried to use AlertDialogs for WearOs and they don't look well, because even if you pass them a custom view, the AlertDialog class crops the layout in some unexpected ways.
How I ended up solving the problem is using the Dialog class (AlertDialog's parent class) and passing it a custom view. The Dialog class doesn't alter the layout and you can attach the dialog to an activity's lifespan (which is the idea of dialogs, creating a custom activity doesn't fit with this requirement).
So you could create a function like this inside your activity:
private void showDialog() {
Dialog dialog = new Dialog(this);
View myLayout = getLayoutInflater().inflate(R.layout.my_layout_id, null);
Button positiveButton = myLayout.findViewById(R.id.positive_button);
positiveButton.setOnClickListener(
v -> {
/* Your action on positive button clicked. */
}
);
Button negativeButton = myLayout.findViewById(R.id.negative_button);
negativeButton.setOnClickListener(
v -> {
/* Your action on negative button clicked. */
}
);
dialog.setContentView(myLayout);
dialog.show();
}
I created a similar fragment with custom layout like this:
Kotlin code:
/**
* Created by nmbinh87#gmail.com on 4/12/21.
*/
class ConfirmationDialog private constructor() : DialogFragment(R.layout.confirmation_dialog) {
var listener: Listener? = null
var longMessage: String = ""
var shortMessage = ""
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tv_longtext.text = longMessage
tv_question.text = shortMessage
tv_longtext.visibility = if (longMessage.isEmpty()) View.GONE else View.VISIBLE
tv_question.visibility = if (shortMessage.isEmpty()) View.GONE else View.VISIBLE
btn_cancel.setSafeOnClickListener {
dismiss()
listener?.onCancel()
}
btn_ok.setSafeOnClickListener {
dismiss()
listener?.onConfirm()
}
}
override fun onStart() {
super.onStart()
val params = dialog?.window?.attributes
params?.width = WindowManager.LayoutParams.MATCH_PARENT
params?.height = WindowManager.LayoutParams.MATCH_PARENT
dialog?.window?.attributes = params as WindowManager.LayoutParams
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
}
open class Listener {
fun onCancel() {
}
open fun onConfirm() {
}
}
companion object {
fun show(
fm: FragmentManager,
longMessage: String = "",
shortMessage: String = "",
listener: Listener
) {
val fragment = ConfirmationDialog()
fragment.longMessage = longMessage
fragment.shortMessage = shortMessage
fragment.listener = listener
fragment.show(fm, fm::class.simpleName)
}
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout 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:background="#color/colorPrimaryDark"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
app:layout_box="all">
<TextView
android:id="#+id/tv_longtext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:fontFamily="sans-serif-condensed"
android:gravity="center"
android:padding="5sp"
android:textColor="#color/white"
android:textSize="16sp"
tools:text="Ambient screen reduces battery life." />
<TextView
android:id="#+id/tv_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="5sp"
android:paddingBottom="15sp"
android:textColor="#color/white"
android:textSize="18sp"
tools:text="Turn on?" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5sp">
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|bottom"
android:src="#drawable/ic_cc_clear"
app:circle_color="#AFAFAF"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:src="#drawable/ic_cc_checkmark"
app:circle_color="#0EB695"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
</FrameLayout>
</LinearLayout>
</android.support.wearable.view.BoxInsetLayout>
Usage:
ConfirmationDialog.show(
childFragmentManager,
"",
"Turn alarm off?",
object : ConfirmationDialog.Listener() {
override fun onConfirm() {
super.onConfirm()
turnAlarm(false)
}
})