Moving a View in a loop - android

I'm trying to make my view move in a loop around 4 corners. I did it by having a keyList. Originally my view is constrained to top and left border.
After each click, I update the keylist by removing first index of keyList and move it to the last.
I have this code currently. The view moves fine for the first 4 corners (1 loop) but the app crashed after.
var keyList = arrayListOf(1,2,3,0,1,2,3,0)
val puckMinX = border.minX().toFloat()
val puckMaxX = (border.maxX() - puck.width).toFloat()
val puckMinY= border.minY().toFloat()
val puckMaxY = (border.maxY() - puck.height).toFloat()
fun clickTextView(view: ImageView) {
if (keyList[0] == 0) {
puck.x = puckMinX
puck.y = puckMinY
var holder =keyList[0]
keyList.remove(holder)
keyList+holder}
else if (keyList[0] == 1) {
puck.x = puckMaxX
puck.y = puckMinY
var holder =keyList[0]
keyList
keyList.remove(holder)
keyList+holder}
else if (keyList[0] == 2) {
puck.x = puckMaxX
puck.y = puckMaxY
var holder =keyList[0]
keyList.remove(holder)
keyList+holder}
else if (keyList[0] == 3) {
puck.x = puckMinX
puck.y = puckMaxY
var holder =keyList[0]
keyList.remove(holder)
keyList+holder}
}
//applying lambda to each textview
puck.setOnClickListener { clickTextView(puck) }
Could someone tell me what I did wrong? Or also is there a better way to make my view move in a loop? Any help is appreciated!
EDIT: I found the problem. My list is only removing the first index but not adding the item that's removed back to the list. How do I update my keylist?

You can use add which adds element to end of the list
keyList.add(holder)
Edit
Note that you wont be able to print like println(keyList.add(holder)) because add will return true since it will successfully update the list. So you will have to do
keyList.add(holder)
println(keyList)

Related

Create list/array of Textviews to change .text via index

So I was hoping to make a list/array of textviews so that I can iterate a loop and set the .text value of the TextViews as I go. Otherwise I would have to set the values in the code statically which would be a whole lot messier and potentially not even feasible for my needs.
So in the code below the idea would be to iterate the loop and when the correct value is confirmed that [index] would then set the corresponding
var refillToken : Double = (0).toDouble()
var tweetStored : BooleanArray = BooleanArray(20)
var tweetActive : BooleanArray = BooleanArray(20)
var userID: MutableList<String> = mutableListOf("")
var textViewToken = 0
while (refillToken > 0) {
var token: Int = 0
while (token < (tweetStored.size)) {
if (tweetStored[token] == true) {
tweetActive[token] = true
textView[textViewToken].text = userID[token]
textViewToken++
refillToken--
token++
if (refillToken < 0) {
break
}
}
}
}
}
I know my loop is probably messy by sane people standards but it makes sense to me and (hopefully) isn't the issue at play. Have found a few articles or ideas searching for the past two hours but they're either 10 years old (and I think deprecated), for java or don't work for whatever reason.
You need to get a value and then add it to the textview and change this value after every action on the page.
Use variable assignment for this task

How do I make cross line in tic tac toe

I made a simple tic tac toe game in Kotlin android studio and I'm Trying to make a line after a won game.
for example if X won all three of X will be crossed with line X̶X̶X̶. My representation of that is Indigent, but I think you got the point.
Progress so far:
made two arrays which hold info about each player:
var Player1 = ArrayList<Int>()
var Player2 = ArrayList<Int>()
var ActivePlayer = 1
var setPlayer = 1
gave id to buttons:
fun buttonClick(view: View) {
val buSelected:Button = view as Button
var cellId = 0
when(buSelected.id) {
R.id.button1 -> cellId = 1
R.id.button2 -> cellId = 2
R.id.button3 -> cellId = 3
R.id.button4 -> cellId = 4
R.id.button5 -> cellId = 5
R.id.button6 -> cellId = 6
R.id.button7 -> cellId = 7
R.id.button8 -> cellId = 8
R.id.button9 -> cellId = 9
}
PlayGame(cellId,buSelected)
}
and this is how I check winner:
fun CheckWinner()
{
var winner = -1
//row1
if (Player1.contains(1) && Player1.contains(2) && Player1.contains(3))
{
winner = 1
}
if (Player2.contains(1) && Player2.contains(2) && Player2.contains(3))
{
winner = 2
}
There is more code to it but its too much to add into this post.
User Interface
I recommend create your own custom view instead of using Buttons. You can for example create FrameLayout and put inside TextView and then either show/hide some simple View with line or draw this line with the help of Canvas. That custom view will be 1 of 9 squares. Then just put them in some grid (manually or using RecyclerView or GridView).
Logic
Create two lists that will contain X and O for each player. Lists of ints with square positions will be enough. Fill those lists with positions (from 1 to 9) when one of two users select a square and before add new item (position) to list, check if this item isn't already in the list (this player, player1) and isn't in the other list (other player, player2). If both of two lists don't contain this item - add it. Then, after adding a new position to list, check if it forms a line. For example, 1, 3, 9 or 2, 5, 7. If so, that player won and you can cross those positions.
Code could look like this:
enum Player {
player1,
player2
}
List<int> player1List = List();
List<int> player2List = List();
void addNewPosition(Player player, int position) {
List<int> currentPlayerList;
List<int> otherPlayerList;
switch(player) {
case Player.player1:
currentPlayerList = player1List;
otherPlayerList = player2List;
break;
case Player.player2:
currentPlayerList = player2List;
otherPlayerList = player1List;
break;
}
if (currentPlayerList.contains(position)) {
// this player already selected this position, do nothing
return;
}
if (otherPlayerList.contains(position)) {
// another player already selected this position, do nothing
return;
}
currentPlayerList.add(position); // add selected position to current player list
// now check if current players position forms a line
if (currentPlayerList.contains(1) && currentPlayerList.contains(2) && currentPlayerList.contains(3)) {
// this player won
}
... check other possible solutions that could result in a win. Better to follow some pattern instead of checking each of them
}

List items iteration speed too slow when having another loop inside

I have two list, one with all possible devices and another with just few devices. I need pass final list with this condition:
if full list == one of the items in smaller list, make this item "active" too true, else leave it false.
I have no problem when working with full list >500 devices and small list >50, but when I have for example 2000 devices everything start to be too slow (on Google Pixel 2XL I need to wait about 6 seconds to job finish).
Question: how can I increase this loop speed?
What I have done so far:
devicesList.forEach { device ->
device.selected = false
items.forEach { it ->
if(it.id == device.id){
device.selected = true
}
}
But this is too slow for larger data
You can speed it up a bit by not using forEach, which uses an interator and instead use a for loop. You can also break once you locate your id, assuming they are unique
for (i in 0 until devicesList.size) {
val device = devicesList[i]
for (j in 0 until items.size) {
val item = items[j]
if (item.id == device.id) {
device.selected = true
break
}
}
}
Assuming your ids are unique, you could also make a duplicate of the items list and drop those that have been located, so each loop is shorter, like this
val copy = items.toMutableList()
for (i in 0 until devicesList.size) {
val device = devicesList[i]
for (j in 0 until copy.size) {
val item = copy[j]
if (item.id == device.id) {
device.selected = true
copy.remove(item)
break
}
}
}
You could also consider creating a map where the key is your id so you do not have to loop and instead you retrieve the item by id directly. You have to weight the cost of creating the map in the first place.
val map = items.associateBy { it.id }
for (i in 0 until devicesList.size) {
val device = devicesList[i]
device.selected = map[device.id] != null
}
Besides this, you should also move your logic to a background thread and wait for it to complete.
If all you need is make selected = true if a device's id exists in the list items, you can get all the ids of items like this:
val ids = items.map { it.id }
and then loop through devices:
devicesList.forEach { it.selected = it.id in ids }

Smart cast to (Int) is impossible, because <variable> is a local variable that is capture by a changing closure

I know this question has been asked before, but it seems there was no resolution. I am trying to keep track of the top visible item in a RecyclerView by with an int variable called topView, which is populated by casting the view's tag (of type 'Any') to an Int:
var topView = citationRecyclerView!!.getChildAt(0)?.tag as Int?
I want that variable to be updated when and if the view scrolls via the onClick of a view:
if (recyclerView.getChildAt((topView + 6)) != null) {
recyclerView.scrollToPosition(topView + 6)
topView = (topView + 6)
}
Each instance of topView in the second code block is giving me the titular error. I understand that it's to prevent the value being changed from another thread, but I only intend for it to be accessed here. How do I compare and increment this Int?
The Kotlin compiler is also subtly pointing out "yo, what should we do if topView is null?".
If the answer is that you want to do nothing if topView is null, you can use ?.let():
topView?.let {
val index = it + 6
if (recyclerView.getChildAt(index) != null) {
recyclerView.scrollToPosition(index)
topView = (index)
}
}

Get the text of a dynamically created textfield in android studio (Kotlin)

So I'm trying to figure out how I would get the text from a dynamically created EditText field.
This is the code for the dynamic Text fields
private fun AddToDoItem() {
val EditText = EditText(this)
EditText.gravity = Gravity.TOP
EditText.gravity = Gravity.CENTER
EditText.tag = "ExtraField" + i
LinearLayout?.addView(EditText)
i++
}
And this is the code where I want to get the Textfields text
Finish.setOnClickListener {
var x = 0
val userId = mAuth.currentUser!!.uid
val mcDatabase = FirebaseDatabase.getInstance().getReference()
mcDatabase.child("Users").child(userId).child(ToDoName.text.toString()).push()
while (x < i) {
val currentUserDb = mDatabaseReference!!.child(userId).child(ToDoName.text.toString())
currentUserDb.child(i.toString()).setValue("ExtraField" + x.text) //HERE IS WHERE I WANT TO SET THE TEXT
x++
Toast.makeText(this, "Finished.", Toast.LENGTH_LONG).show()
}
}
Where its commented like "//HERE IS WHERE I WANT TO SET THE TEXT" is where I want the .text string.
(It's in the while loop)
There are two ways to handle this:
You are adding the EditText's to a LinearLayout therefore you can iterate over its children - as described here and therefore replacing the while loop.
The second way would be to add the EditText's to a List<EditText> and iterate over it, replacing the while loop.
The first solution would probably be cleaner, but both of them work in a very similar fashion.
Hope this helps you!

Categories

Resources