Boolean turns into int number 904 in Kotlin - android

I'm working on a quiz app for my project at university, and I'm trying to save button and boolean that states if the answer is correct or not in data class and save all buttons in a temporary list so I can add onclick listener for all of them later. But when I'm trying to access boolean value, it just turns into number 904. Here's my code regarding these buttons.
val ansBtnList: MutableList<ButtonDataClass> = mutableListOf()
--------------------------------------------------------------
val ans = ButtonDataClass(Button(this), quizToShow.getValue(planets[0]).answers[i].isRight)
--------------------------------------------------------------
ansBtnList.add(ans)
--------------------------------------------------------------
for (i in 0..3) {
ansBtnList[i].btn.setOnClickListener { Log.d(null, ansBtnList[i].btn.right.toString()) }
}
Thanks in advance!
EDIT: ButtonDataClass code:
data class ButtonDataClass (var btn: Button, var right: Boolean)

It's not the right that you think it is. btn is the button. The button has a right field that is related to its coordinate on screen. You should try ansBtnList[i].right.toString() instead.

btn.right refers to right variable of Button class, not to the one present in the ButtonDataClass
replace: ansBtnList[i].btn.setOnClickListener { Log.d(null, ansBtnList[i].btn.right.toString()) }
with: ansBtnList[i].btn.setOnClickListener { Log.d("your_tag_id", ansBtnList[i].right) }

Of course you are not accessing the right field. ansBtnList[i].btn.right gives you the right position of your button in pixels.
Rather do ansBtnList[i].right

Related

how to assign a condition to an imageView by using if else?

I tried to show a random imageView out of 2(one,two) with this
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)]) it works fine
and
i wanted to increase score when i clicked on imageView
but score increases independent to that, sometimes increases when i clicked on imageView2 and sometimes imageView, i want to increase score when i only clicked on imageView. i couldnt figure out. Thanks in advance.
var score = 0
val oneandtwo: IntArray = intArrayOf(
R.drawable.ic_baseline_looks_one_24,
R.drawable.ic_baseline_looks_two_24
)
binding.imageView.setOnClickListener{
val random = Random
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)])
if (oneandtwo[random.nextInt(oneandtwo.size)]==(R.drawable.ic_baseline_looks_one_24)){
score++
binding.textView.text = score.toString()
}
}
The number you gave in the image and the number you checked in the if block may not match and will not give the result you want. If you change code like this. Probably your problem will be solved.
binding.imageView.setOnClickListener{
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
if (oneandtwo[random]==(R.drawable.ic_baseline_looks_one_24)){
score++
binding.textView.text = score.toString()
}
}
What you are doing is checking the resourceId of the newly generated image, not the one you just clicked. That's why it not giving the result you want ,i.e, increment on the click of imageView and not on click of imageView2. Try below code. it should work
var score = 0
val oneandtwo: IntArray = intArrayOf(R.drawable.ic_baseline_looks_one_24,R.drawable.ic_baseline_looks_two_24)
/*Initalize the initial image and tag either here or in xml file*/
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
binding.imageView.Tag = oneandtwo[random]
binding.imageView.setOnClickListener{
val imageTag = binding.imageView.Tag
if (imageTag == (R.drawable.ic_baseline_looks_one_24)) {
score++
binding.textView.text = score.toString()
}
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
binding.imageView.Tag = oneandtwo[random]
}
You've got two problems that both the answers cover - if clicking a particular image is meant to give you points, you have to check the image before you change it. And if you're using random items, you need to pick one and keep a reference to it. This:
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)])
if (oneandtwo[random.nextInt(oneandtwo.size)]==(R.drawable.ic_baseline_looks_one_24))
picks two completely independent numbers which may not match - and they're supposed to be referencing the same item, right? Get your random thing once, use it twice
RahulK's answer should work but here's another way you could do it, with an explicit listener object so you can throw a state variable in there:
binding.imageView.setOnClickListener(object : View.OnClickListener {
// keep track of whether the current image adds to the score when clicked
var givesPoints = false
override fun onClick(view: View) {
// first, we just got clicked, so add to the score if appropriate
if (givesPoints) score++
// you can just call random() on a collection to get a random element from it
val resId = oneAndTwo.random()
// set the image - might be better to do (view as ImageView).setImageResource
// so it sets it on -whatever was clicked- so it's easier to reuse
binding.imageView.setImageResource(resId)
// now set whether this new image gives points or not
givesPoints = resId == R.drawable.ic_baseline_looks_one_24
}
})
So this way, every time you set a new image, the listener knows whether to give points for it next time it's clicked
I don't know how you have this set up, you're only initialising things when the image is clicked so if you need to set them up beforehand (so you can have an image displayed that you an click for points) you probably want everything in a separate function you can call when clicked and during setup:
/** Assigns a random picture to this ImageView - returns true if it's a point-scoring pic */
fun assignRandomPic(imageView: Imageview): Boolean {
val resId = oneAndTwo.random()
imageView.setImageResource(resId)
return resId == R.drawable.ic_baseline_looks_one_24
}
// set an initial image, storing whether it scores points
val scoreMe = assignRandomPic(binding.imageView)
binding.imageView.setOnClickListener(object : View.OnClickListener {
// initialise this as appropriate for the image we just set up
var givesPoints = scoreMe
override fun onClick(view: View) {
if (givesPoints) score++
// set a new pic and store its point-scoring state
givesPoints = assignRandomPic(view as ImageView)
}
})
or you could just do var givesPoints = assignRandomPic(binding.imageView) and init the image inside the click listener, whatever feels better

Best practice for assigning a button text and click listener Android/Kotlin

let's say we have a dynamic button that will have text and clicklistener assigned based off of our server response.
I was wondering the cleanest approach and best practice for assigning this button.
Based off of the server response, my first approach is to assign an enum to our dataclass that will be used by our view layer. This enum tells us what type of button this should be, and based off of this type, we will have a specific text and button click listener for each.
Is this approach so far good or is there a better way to start?
And what is the best way to assign the button data? Should I have maybe a Pair (or other data class?) that will store the text and click listener and have when statement that will make the assignment based off the enum?
What to you guys think is the best approach and will produce the cleanest code?
This would be in Kotlin.
I think that the cleanest way for your case is to use polymorphism, let's say that you will have 3 types of buttons:
SumButton: will receive two numbers, sum them and return the result
MultipleButton: will receive two numbers, multiply them and return the result
DivideButton: will receive two numbers, divide them and return the result
Let's see how we can do this with polymorphism:
Create a sealed class that will hold the different button types, and when you need to add another type of button you just need to add it to the sealed class:
sealed class ButtonType(
open val buttonText: String,
open val buttonClickListener: (x: Int, y: Int) -> Int
) {
object Sum : ButtonType(
buttonText = "Sum numbers",
buttonClickListener = { x, y ->
x + y
}
)
object Multiply : ButtonType(
buttonText = "Multiply numbers",
buttonClickListener = { x, y ->
x * y
}
)
object Divide : ButtonType(
buttonText ="Divide numbers",
buttonClickListener = { x, y ->
x / y
}
)
}
You can use that button type like this:
/**
* Response
*/
// Return the button type that you want depending on the response
val buttonType = ButtonType.Multiply
/**
* Fragment
*/
// Set button text
button.text = buttonType.buttonText
// Set button click listener
button.setOnClickListener {
val result = buttonType.buttonClickListener(4, 6)
Log.d("result", "$result")
}
Here's a kind of standard approach
enum class ButtonState(#StringRes val labelResId) {
ONE(R.string.button_one_label),
TWO(R.string.button_two_label)
}
private fun updateButton(button: Button, type: ButtonState) {
// assign the label from the data -held in- the enum constant
button.text = getString(type.labelResId)
// define click listeners here and assign -depending on- the enum constant
when(type) {
ONE -> { doThing() }
TWO -> { doOtherThing() }
}.run(button::setOnClickListener)
}
so you basically have your enum with some data for each state, and then you have a function that applies a particular state to a button instance. When you need to change state, you call the function again.
But if you like, you could roll that into the enum itself:
enum class ButtonState(#StringRes val labelResId, val listener: (View) -> Unit) {
ONE(R.string.button_one_label, {
// you could write out your listener code here
}),
// or pass a reference to a function and keep your code in there
TWO(R.string.button_two_label, ::someListenerFunction);
// function that applies this enum constant's state to a button
fun applyTo(context: Context, button: Button) {
button.text = context.getString(labelResId)
button.setOnClickListener(listener)
}
}
fun someListenerFunction(view: View) {
// do stuff
}
and when you want to update your button's state
ButtonState.TWO.applyTo(context, button)
It's basically the same thing, it just depends if you prefer to have everything encapsulated in the state object, or if you want a more functional approach
The nice thing about enums too is they're Serializable, so you can easily pass the current state around, store it in a SavedStateHandle etc

Select buttons more than one kotlin and using variables in findViewById() - android studio

I want to do actions with 9 buttons.Is there anyway to do action with 9 buttons in one time,not one by one.
If I could add variable to findViewById() I would solve problem.
For example I want to select 9 button at once(with for loop) like below
for(i in 1..9){
findViewById(R.id.button+i).text="New Text"
}
This way not working,please suggest optimal ways.
I want like this in javascript equivalent:
document.getElementById("button"+i)
Declare this in your activity:
var buttons: ArrayList<Button> = arrayListOf()
and in onCreate():
for (i in 1..100) {
buttons.add(findViewById<Button>(resources.getIdentifier("button" + i, "id", this.getPackageName())))
}
Now you have all your buttons in a list.
if you want to change the state of your buttons, say disable them all:
buttons.forEach { it.isEnabled = false }
You can set tag for each button (like button1, button2, etc.) and do something like this
for(i in 1..9){
(view.findViewWithTag("button"+i.toString()) as Button).text = "New Text"
}

Espresso set cursor for edittext

I am trying to test an EditText that already contains some text using Espresso. The problem is that when I use typeText(), the cursor is placed at an arbitrary position within the text. I tried performing click() before using typeTextIntoFocusedView but the cursor is sometimes placed at the beginning of the EditText. I want to know is it possible to set the cursor at the end of the EditText before typing text into it?
A better way would be to use Espresso the way it's meant to be used: with actions on view matchers.
Example in Kotlin:
class SetEditTextSelectionAction(private val selection: Int) : ViewAction {
override fun getConstraints(): Matcher<View> {
return allOf(isDisplayed(), isAssignableFrom(EditText::class.java))
}
override fun getDescription(): String {
return "set selection to $selection"
}
override fun perform(uiController: UiController, view: View) {
(view as EditText).setSelection(selection)
}
}
Example usage:
onView(withId(R.id.my_text_view).perform(SetEditTextSelectionAction(selection))
An extra advantage over manually doing findViewById() is that you can combine this with matchers like withSubString("my text") if you don't have the ID of the view.
By the way: to change this into setting selection at the end of text you can simply remove the selection: Int constructor argument and change setSelection(selection) to setSelection(view.text.lastIndex).
The only way I have found to do this is to get a reference to the EditText itself and use EditText#setSelection(). For example, to move the cursor to the end of the current text:
val activity = activityRule.activity
val tv = activity.findViewById<EditText>(R.id.edittext)
activity.runOnUiThread { tv.setSelection(tv.text.length) }
I've had success by inserting the KeyCodes for "Home" and "End". These work just like on your desktop keyboard, by moving the cursor to either the beginning or end of the EditText. For example:
onView(withId(R.id.myView))
.perform(pressKey(KeyEvent.KEYCODE_MOVE_HOME))
To move to the end, you can use KeyEvent.KEYCODE_MOVE_END, and you can move left or right using KeyEvent.KEYCODE_DPAD_LEFT and KeyEvent.KEYCODE_DPAD_RIGHT.
I wanted to post my answer since I just had this problem and none of the other answers solved my problem.
I used a GeneralClickAction to click on the right side of the edit text which put the cursor at the end of the EditText where I wanted it. After that I used the TypeTextAction and disabled the tapToFocus behavior by passing in false to the constructor:
onView(withId(R.id.edit_text))
.perform(
new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER_RIGHT, Press.FINGER, 0, 0, null),
new TypeTextAction(text, false)
);

Calculator button (Android) - Distinguishing between normal click and longClick (for sine and arc sine functions)

Below I've listed two functions. I have a button for "sine" function - which works perfectly and on LongClick I want to add the sine inverse function or arc sine.
***NOTE : The difference between the two functions below is just the one line where I assign afterSin variable, in one I use Math.sin in the other - Math.asin, that's it no more difference.
The problem is , normal click or long Click , I'm getting the "Sine" function only, even though I've coded asin function, I don't why but it seems to ignore it and gives the normal click function. (Again, on longClicking it doesn't give the arc sine function as I want it to, but simply gives the normal function "sine" , that is the same as normal OnClick function.)
Here's the normal OnClick :
public void onClickListener_sin(View v) {
vibrator.vibrate(30);
EditTextMsg = editText.getText().toString();
doubleEditTextMsg = Double.parseDouble(EditTextMsg);// degree
toRadian_doubleEditTextMsg = Math.toRadians(doubleEditTextMsg);
afterSin = Math.sin(toRadian_doubleEditTextMsg);
////////Only different line is the above one (Sin, here and ASin below )
editText.setText(afterSin.toString());
EditTextMsg = editText.getText().toString();
result = Float.parseFloat(EditTextMsg);
result_mul = Float.parseFloat(EditTextMsg);
result_div = Float.parseFloat(EditTextMsg);
sum = "";
}
AND
Here's the LongClick function (I want it to give asin, but it ignores the function and continues with the normal(above function and gives me "Sine" )
button_sin.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
vibrator.vibrate(30);
EditTextMsg = editText.getText().toString();
doubleEditTextMsg = Double.parseDouble(EditTextMsg);// degree
toRadian_doubleEditTextMsg = Math.toRadians(doubleEditTextMsg);
afterSin = Math.asin(toRadian_doubleEditTextMsg);
///////////////The above line is the only difference between this and the above ///////////function
editText.setText(afterSin.toString());
EditTextMsg = editText.getText().toString();
result = Float.parseFloat(EditTextMsg);
result_mul = Float.parseFloat(EditTextMsg);
result_div = Float.parseFloat(EditTextMsg);
sum = "";
return true;
}
});
I'm showing the results and inputs in a EditText box ...
(The result, result_mul, sum variables should not be relevant to this question, I copied them anyways because they are used for the respective functions in my calculators specific code... It shouldn't be related to the current problem)
So, Can you spot anything wrong ?
(It ignores the onLongClick....and simply carries out the normal Onclick function (The same function whether the click is normal or long)
Thank you.
It may help to enable the button's long-clickable attribute
button_sin.setLongClickable(true); // CODE
OR
android:longClickable="true" // XML
Then as pointed out by #Opiatefuchs, you should really be calling .setOnLongClickListener() in the same way as you provide the .setOnClickListener() for neatness' sake.
Hope it helps!

Categories

Resources