Dynamically add TextViews to FlipperView with varying ScrollY - java

I am developing an app and have begun learning Java a few weeks ago. At this point, there's something that I'm trying to get to work, but I can't figure out what's going wrong.
So the problem is as follows. I have a FlipperView in which I want to dynamically add TextViews between which I should be able to navigate. These TextViews have the same content and layout, the only difference between them is their "ScrollY" attribute. I want the first TextView to have a ScrollY of 0 so that the text can be seen from its beginning. Then, I want the next TextView to have a ScrollY of 0 + x, where x is the height of the TextView (which is originally defined as match_parent). The next one should have a ScrollY of 2x, etc.
I've tried many things to get this work. First I managed to dynamically get the height of the TextView using a .post. For now, I can change the ScrollY of the first TextView. For additional views, I'm using a for a loop. At this point, TextViews are properly created and I can navigate between them with the FlipperView. However, the SetScrollY function doesn't work inside the for loop. I've tried to feed it with an arbitrary integer instead of the dynamic height of the TextView without success, so I guess the function is not working at all in this case. Here's my code (the number of loops is fixed for now):
public int formatText(Context context, ViewFlipper textFlipper) {
int nbOfViews = 1;
final int[] viewMaxHeight = {0};
final int[] lineSpacing = {0};
textContent = context.getResources().getString(R.string.dummyText);
final TextView flipperView = new TextView(context, null, R.style.flipperText);
flipperView.setText(textContent);
textFlipper.addView(flipperView);
flipperView.post(new Runnable() {
#Override
public void run() {
viewMaxHeight[0] = flipperView.getHeight();
lineSpacing[0] = Math.round(flipperView.getLineSpacingExtra());
}
});
for(int i = 0; i < 2; i++) {
TextView flipperViewExtra = new TextView(context, null, R.style.flipperText);
flipperViewExtra.setText(textContent);
flipperViewExtra.setScrollY(viewMaxHeight[0] * nbOfViews + lineSpacing[0]);
textFlipper.addView(flipperViewExtra);
nbOfViews++;
}
return nbOfViews;
}
Any help is appreciated, thanks!

You are working with THREAD and thread tends to optimize the performance by caching the using variables. Hence any chance OUTSIDE the thread it won't "see" the change in memory. To coerce the thread to look at the change in memory you have to declare the variables to volatile. Example
final volatile int[] viewMaxHeight = {0};
final volatile int[] lineSpacing = {0};

Related

How can I get and set a string resource dynamically in a for-loop using a findViewById() method?

In my app, I want a counter from 0 to 8 to decide the number of players in a game.
Below there are 8 possible fields to write a name inside, which are all set to invisible. If the players-counter is set to 3 players, there should be the first 3 fields visible. Depending on the actual number of the counter, the visibility of the fields changes (1player = first field, 5 players = first 5 fields).
When the +1 (player) button is clicked, a certain method is activated. I tried to run a for-loop everytime the button is clicked. In this for-loop from 0 to "whatever amount" (max. 8 players) the actual fields should be found with "findById" and set to visible.
I tried it with a string resource (.xml) and I can get the text of the resource but with my thought process, I have to update the string resource to every number of the field (if 3 players: "field_" + "1", "field_" + "2", "field_" + "3").
How can I get and (most importantly) set/update a string resource for this specific purpose?
(Switch is too inefficient and I can't use a string with the findViewBy Id()-method by updating the String (not string resource) like mentioned before.
Please help, and accept the fact that I'm new to Android Studio for one week!)
You can use "getIdentifier" which takes a String parameter. So you can set the type as "id" in the second parameter of this method. This method returns the id of the view you want, but beware, it will throw a "FATAL EXCEPTION" if the id of the View doesn't exist. With this id, you can use findViewById to fetch the TextView and change its visibility. The "getIdentifier" method can be called from the "getResources()" method.
Below you can see what it would be like to make visible a TextView that has the id "textView1":
int id = getResources().getIdentifier("textView1", "id", getPackageName());
TextView textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
Below you can see how you would make 8 TextView with id 1 to 8 visible:
TextView textView;
for (int i = 1; i <= 8; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
So, just put the limit at i <= x , with x being the limit of players who will play:
TextView textView;
for (int i = 1; i <= totalPlayers; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
Do you just want to make some EditTexts visible and others not? Personally I'd keep it simple, do the lookups once (in onCreate or wherever) and store the references in a list. Then when you need to display n fields, you can just iterate over the list and set the first n to VISIBLE and the rest to INVISIBLE.
I feel like it's fine to just list all the EditText IDs (R.id.field_1 etc) and generate your list of actual Views from that, but if that repetition bothers you, there's a few things you could do. Like:
set a tag attribute on each field in the XML, and use findViewWithTag to look them up, generating the lookup strings programmatically, like "field_" + i
do a similar thing with the resource ID, like in #Moises's answer
lookup their containing layout, use getChildCount and [getChildAt] to iterate over the views in that layout, and use isInstance to collect all the EditTexts in order3
create and add the EditTexts in code - you probably don't want to do this, but you could!
I'm not really sure what you mean about the string resource or what you're trying to do - I'd honestly just make a list of R.id.field_1 etc, iterate over that to do findViewById on each and store those in a new list, and you're done. Also my Java's a bit rusty so sorry no example code!

Java - dynamically build textview reference

New Android/Java coder. Trying to replicate in Android app a project I built in MS-Access.
I have a layout with similar named TextViews, like text10, text12, etc. In MS-Access I can dynamically build those names with collection referencing:
For X = 10 To 15
Me.Controls("text" & X) = Null
Next
There is no array required. So looking for structure in java that can accomplish the same functionality.
I want to dynamically set background color of multiple TextView based on two inputs. One is to build TextView reference and the other is a state indicator that will determine color.
Here is one procedure calling setSubColor:
public void Clear(MenuItem mi) {
puz.setText("");
sol.setText("");
for (int i=0; i<26; i++) {
setSubColor(aryA[i].charAt(0), 0);
What I have so far for setSubColor:
public void setSubColor (char c, int i) {
TextView v = (TextView) >>>dynamically reference v using name built with ("tv" + c)
if (i == 0) {v.setBackgroundColor(Color.TRANSPARENT);}
else {v.setBackgroundColor(Color.YELLOW);}
You can get the res id from the res name at runtime. So if your textview had name "text1", you could get the integer id by using:
int id = getResources().getIdentifier("text1", "string", getPackageName());
TextView view = findViewById(id);
But do so only as a last resort, it's error prone, slow and somewhat of an anti pattern.
EDIT by OP: No matter what the name argument is always returns 0 but marked as answer because it led to the following code that works exactly as I want, anti-pattern or not.
TextView v = (TextView) findViewById(getResources().getIdentifier("tv" + c, "id", getPackageName()));
Instead of the TextView Id field use its Tag field.
String tag = (String)textView.getTag() and textView.setTag(Object tag) with tag instanceof String
then you can find the TextView by Tag

I want an image to fade out and the another to fade in when it is clicked and after that the other way around

The code below is supposed to fade two ImageViews, one needs to fade in and the other out depending on the value of counter. For some reason when I run the code I get the following log output:
I/Info: One
I/Info Counter:: 1
I/Info: One
I/Info Counter:: 1
...
It never shows:
I/Info: Two
I/Info Counter:: 0
Can someone explain why this is happening?
Here's the code:
public void fade(View view) {
int counter = 0;
ImageView bale = (ImageView) findViewById(R.id.bale);
ImageView pogba = (ImageView) findViewById(R.id.pogba);
if (counter == 0) {
bale.animate().alpha(0f).setDuration(2000);
pogba.animate().alpha(1f).setDuration(2000);
Log.i("Info", "One");
counter = 1;
} else if (counter == 1){
pogba.animate().alpha(1f).setDuration(2000);
bale.animate().alpha(0f).setDuration(2000);
Log.i("Info", "Two");
counter = 0;
}
Log.i("Info Counter: ", String.valueOf(counter));
}
You're making a logical error, there is nothing syntactically wrong with your code. The scope of counter is where you're having trouble. counter is a local variable, it only exists in the fade(...) method. Every time you call fade() you recreate counter and initialize it to 0. Meaning even though you set it to 1 in the if statement, it will be 0 the next time you call fade(). You either need to make it a class variable or use the alternating approach I describe below.
Non If Statement Alternating Approach:
You don't need an if statement, simply get the alpha of pogba and bale and then when you set their alphas use 1f - pogba.getAlpha() and 1f - bale.getAlpha() (using whichever method returns their alphas). Using this approach will alternate between 1 and 0.
So your fade(View view) method would look similar to the following:
public void fade(View view) {
ImageView bale = (ImageView) findViewById(R.id.bale);
ImageView pogba = (ImageView) findViewById(R.id.pogba);
// I'm not familiar with the method to get the alpha
// so it might not be getAlpha()
bale.animate().alpha(1f - bale.getAlpha()).setDuration(2000);
pogba.animate().alpha(1f - pogba.getAlpha()).setDuration(2000);
}
You would of course need to do the following somewhere else in your code, possibly the constructor.
bale.setAlpha(1f); // I'm not familiar with the method to set the alpha
pogba.setAlpha(0f); // it might be setAlpha(), but I'm not sure

Attempting to exchange two sections of an image

I am trying to swap the values of two sections of an image in a specific fashion: I want to move one block of pixes to the right 225 pixels, and take the block that was there and move it to the left 225 at the same time. However, it looks like the only transformation that takes hold is the first one:
public void exchange() {
int[][] stablePic = picArray.clone();
for (int i = 80; i < 230; i++)
{
for (int j = 50; j < 250; j++)
{
picArray[i][j] = stablePic[i][j+225];
picArray[i][j+225] = stablePic[i][j];
}
}
}
"picArray" is initialized earlier in the code - this compiles and runs, but only makes the first exchange - the second portion of the image still has the appearance of the first portion. Is there any way to have both transformations take place at once?
Are you sure the second fragment is the only one working? It seems to me that is the first one which is working.
To copy one array to other array don't just assign it. Use 2 for-loops for this, and when you see it works, investigate about how to replace the inner for-loop with Arrays.copyOf.
Here you have:
int[][] stablePic = picArray;
Which makes both variables point to the same memory, then when you modify your picArray you are modifying your stablePic also.
You are trying to swap two sections of an image for understanding purpose just take it as how can you swap two variables i.e
int a=10;
int b=20;
int temp ;//take a temp variable for swapping
temp =a;
a=b;
b=temp;
like this you have to take a temporary array.For swapping .in your code second one is working because it is overriding with the previous one.

What is the purpose of variable duplication in a method?

I see this [below] all over in the Android code (and some other code sources). What is its point or purpose?
class Foo {
int mBar = 1337;
static void main(String... args) {
System.out.println(isFubar());
}
boolean isFubar() {
int ret = mBar; // <--- Focus of attention
if (ret == 666)
return true;
else
return false;
}
}
It seems like a waste of time and resources. mBar clearly isn't being modified. There is no risk of it being modified (in the given context), so why would one duplicate the primitive just to preform a noninvasive check on it and return?
EDIT Specific example from the class CellLayout in the Android Source
public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) {
final boolean portrait = mPortrait; <--- Here it is
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
final int widthGap = mWidthGap;
final int heightGap = mHeightGap;
final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
int x = hStartPadding + cellX * (cellWidth + widthGap);
int y = vStartPadding + cellY * (cellHeight + heightGap);
dragRect.set(x, y, x + width, y + height);
}
Perhaps for multi-threading. If the value of mPortrait changed between the following two lines you would have mixed results.
final int hStartPadding = mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding;
final int vStartPadding = mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding;
For example:
final int hStartPadding = true ? mShortAxisStartPadding : mLongAxisStartPadding;
// somehwere else: mPortraint = false
final int vStartPadding = false ? mLongAxisStartPadding : mShortAxisStartPadding;
A few ideas come to mind.
The expression needed to retrieve the class member variable might be really complicated (your example is not), so saving it in a local variable might be more readable.
It is possible that storing it in a local variable is more efficient, especially if the method has to access the value more than once. (Your example does not do this.)
Retrieving the value once gets its value at that moment in time, and not some later value that another thread may have modified in the meantime.
Storing it in a local variable makes it easy to examine with a debugger.
For your particular example, only reason (4) makes any sense.
I use it so i can modify the variable in recursion or loops and not mess with the original one. It also helps with passing the variables between classes and other methods.
Also, if it is changed while the method is running, the method will not mess up, it will continue with the variables it started with. I had this major problem while multi-threading my graphics printing and code. The code would change variables and weird stuff would happen on the screen.
I don't know about hardware or speed, but on the code side, it makes it very simple and flexible in many cases.

Categories