Hey this is my first time trying anything like so I don't know if this is even close to the best way to do this, but I thought it would work. I'm trying to go through the XML layout file and set all TextView's to be INVISIBLE. When the following method is called I get a NullPointerException
public void numPlayerSetup(){
{
for(int i = 3; i <= 6; i++)
for(int z = 2; z <= 10; z++){
int resID = getResources().getIdentifier("TextView"+Integer.toString(z) + Integer.toString(i), "id", this.getPackageName());
if(resID != 0){
TextView text = (TextView) this.findViewById(resID);
text.setVisibility(View.INVISIBLE);
}
}
Let me know if you have any suggestions. Thanks!
Well, are the ids going to change? If not, just set up an int[] of TextView IDs, and loop through those, e.g.:
int[] ids = {
R.id.tv1, R.id.tv2, R.id.tv3 //...
}
for(int i : ids) {
TextView tv = (TextView)findViewById(i);
tv.setVisibility(View.INVISIBLE);
}
I would definitely not try using reflection, it'd be a lot less efficient than doing it in other ways. If you don't know the IDs of the TextViews ahead of time, why not try something like this (assuming your root layout is a RelativeLayout):
RelativeLayout root = (RelativeLayout)findViewById(R.id.root);
for(int i = 0; i < root.getChildCount(); i++) {
View v = findViewById(i);
if(v instanceof TextView) {
((TextView)v).setVisibility(View.INVISIBLE);
}
}
Since you've already accepted, I'll assume method 1 worked, because I just realized I was horribly off on method 2. It should be getChildAt(i), not findViewById(i), as that would just be calling findViewById(0|1|2|...etc). Below is a corrected version:
RelativeLayout root = (RelativeLayout)findViewById(R.id.root);
for(int i = 0; i < root.getChildCount(); i++) {
View v = root.getChildAt(i);
if(v instanceof TextView) {
((TextView)v).setVisibility(View.INVISIBLE);
}
}
I haven't tested that, but it sounds good in theory. :)
Did you do some debugging?
For instance, have a look if the resIDs match. At least they're not zero, if your error occurs right there. (Have you checked that?).
It may sound odd, but you could also check if getResources() and this.findViewById() refer to the same object.
That's all I can think of for the moment.
As the others have indicated, the most obvious cause of a NullPointerException would be that you're not checking if text is null before calling setVisibility(). You'll want to look into why text would be null in the first place- but you should check your pointers regardless.
Or just go with kcoppock's alternative.
Any particular reason you're using setVisibility? It isn't always appropriate- I believe all it does is keep draw from being called, which can cause issues later if you hoped to treat it as drawn but invisible.
Related
I have a layout which is something like this:
LinearLayout (linearLayout)
'--TextView (textView1)
'--ImageView (imageView)
'--TextView (textView2)
textView1 changes its text sometimes and it can be long, so it leaves part of textView2 out of the screen. I want to prevent that, so I want to remove imageView from the layout whenever this happens. imageView may or may not be visible at the time when this is computed (maybe it was removed before when textView1 was edited previously).
This is what I have coded:
void changeText(String veryLongString){
textView1.setText(veryLongString);
int [] loc = new int [2];
textView2.getLocationOnScreen(loc);
int bottom = textView2.getMeasuredHeight() + loc[1];
if (imageView.getVisibility() == View.GONE)
bottom += imageView.getHeight();
if (bottom > linearLayout.getMeasuredHeight()){
imageView.setVisibility(View.GONE);
} else {
imageView.setVisibility(View.VISIBLE);
}
}
But for some reason this doesn't work as expected, because it seems as if changes in the position and height of the Views don't take place immediately. When I call getMeasuredHeight() and getLocationOnScreen() I get the values BEFORE the changes I have just made. The result that I get is that if I set a very large text imageView is not removed, but if I then set a short text, it is removed.
If there any other way to face this problem?
Even though I think that this is not the right approach (you can do all kinds of stuff in your XML so you don't have to meddle with Java code), here is a quick example of what you can do from Java (for example, in your onStart() method)
ViewGroup group = (ViewGroup) findViewById(R.id.myLayout);
int groupHeight = group.getHeight();
for (int i = 0; i < group.getChildCount(); i++) {
groupHeight -= group.getChildAt(i).getHeight();
if (groupHeight < 0) {
// they don't fit in the layout
myImageView.setVisibility(View.GONE);
}
}
Acquiring a view in the hierarchy I have both of these functions available. While findViewById is easier to use, I often saw suggestions that it can be an expensive operation and should be avoided if possible.
Therefore, would it be any quicker to use getChildAt instead? Is there any guideline as to when it is better to use which?
findViewById vs getChildAt - which one is quicker?
getChildAt is indeed faster than findViewById, since it is just accessing an array of Views at the specified index.
Therefore, would it be any quicker to use getChildAt instead
it will indeed, but you have to know the index of the View you are looking for. If you don't have any mechanism to keep track of the index, than you have to look for it, and you got back to findViewById. You will probably ended up re writing your own version of findViewById. My two cents, don't worry about that.
Looking at ViewGroup implementation findViewById will eventually loop through children and compare id so I suggest to just use the findViewByIdmethod.
#Override
protected View findViewTraversal(#IdRes int id) {
if (id == mID) {
return this;
}
final View[] where = mChildren;
final int len = mChildrenCount;
for (int i = 0; i < len; i++) {
View v = where[i];
if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
v = v.findViewById(id);
if (v != null) {
return v;
}
}
}
return null;
}
I am creating lots of view dynamically and adding them to my RelativeLayout. I need to keep track of all of these views so I can remove them later, so I add them is an ArrayList. But when I try to remove them all from the layout, they are not all removed.
ArrayList<LineView> lineChain = new ArrayList<LineView>();
LineView linkLine;
RelativeLayout wrapper; // Removed params etc.
// Later on in code
// This occurs many times
linkLine = new LineView(getApplicationContext());
wrapper.addView(linkLine, rlp);
lineChain.add(linkLine);
This is what I do when I try to remove all of the views. This only happens once:
for (int i = 0; i <= lineChain.size() -1; i++) {
LineView lv = lineChain.get(i);
wrapper.removeView(lv);
lineChain.remove(i);
}
As I said, the problem is that not all the lines are removed - I havn't managed to work out the pattern for which are deleted and which aren't.
You have a bug in your remove code.
for (int i = 0; i <= lineChain.size() -1; i++) {
LineView lv = lineChain.get(i);
wrapper.removeView(lv);
lineChain.remove(i);
}
The documentation for ArrayList.remove(int) function says:
Removes the element at the specified position in this list. Shifts any
subsequent elements to the left (subtracts one from their indices).
When you remove an item at an index i, all the remaining elements are shifted to the left. So for example if you remove an element at position 0. The element at position 1 is shifted to position 0 and is never removed (because you are incrementing i).
The your code to this:
while (!lineChain.isEmpty()) {
LineView lv = lineChain.get(0);
wrapper.removeView(lv);
lineChain.remove(0);
}
I think that the problem is while removing the element from the List after the cycle.
You should do something like this:
for (LineView lv : lineChain) {
((RelativeLayout) namebar.getParent()).removeView(namebar);
}
If you want to get rid of all the elements, just reset the list
lineChain = new ArrayList<LineView>()
I did get the drag and drop working and the TouchListView class works great. However in my case I have rows of various height due to my adapter which contains an EditText that can have multiple lines. Therefore after I drop, all my rows convert to the tlv:normal_height which in my case is 74dip. This causes many rows to cut off all my text in the EditTexts. I tried re initializing my adapter (mylistview.setAdapter= myadapter), setting the ListView to GONE then VISIBLE and invalidateViews() but nothing seems to reset the ListView back to before I dragged, short of leaving the activity and coming back. What can be done here? -Thx
tlv:normal_height="74dip"
tlv:expanded_height="128dip"
There's little question that the original AOSP code was designed for uniform row heights, and the whole expanded_height construct was there to provide space for the user to visualize where the drop would occur.
One starting point would probably be to create a TouchListAdapter mixin interface (akin to SpinnerAdapter) where the normal_height and expanded_height would be retrieved dynamically from the adapter based on position as opposed to being fixed values declared in the layout. Whether that alone would be sufficient or more work would need to be done, I can't say.
If you come up with a solution, patches are welcome. Otherwise, I'll probably take a look at this sometime, but not very soon.
My apologies for not having a near-term silver bullet.
I edited the unExpandViews() method - called getAdapter() and for every item in my adapter set the height to 0 and then all the rows were set back to original. I also bypassed the delete part of the method since it did not apply to me.
private void unExpandViews(boolean deletion) {
int height_saved = 0;
CheckBoxifiedTextListAdapter cbla = (CheckBoxifiedTextListAdapter)getAdapter();
for (int i = 0;i < cbla.getCount(); i++)
{
//View v = getChildAt(i);
View v = cbla.getView(i, null, null);
//if (v == null)
//{
/*
if (deletion)
{
// HACK force update of mItemCount
int position = getFirstVisiblePosition();
int y = getChildAt(0).getTop();
setAdapter(getAdapter());
setSelectionFromTop(position, y);
// end hack
}
layoutChildren(); // force children to be recreated where needed
v = getChildAt(i);
if (v == null)
{
break;
}
height_saved = v.getHeight();
*/
//}
//else
//height_saved = v.getHeight();
if (isDraggableRow(v))
{
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = 0;
v.setLayoutParams(params);
v.setVisibility(View.VISIBLE);
}
}
}
Does anyone have a quick and easy method for removing dynamically added buttons from a Linear Layout in Android? They seem to be kept in the saved instancestate and I don't want them when I return to the activity.
You may clear ALL views in a linear layout by using the following code:
LinearLayout myLayout = (LinearLayout)findViewById(R.id.your_linear_layout);
myLayout.removeAllViews();
However, if you are looking to remove only the views that were dynamically added (and you have views in there that are not) this will not work.
If you need to do it this way you can do something like this
LinearLayout l = (LinearLayout)findViewById(R.id.linearLayout);
List<View> removeViews = new ArrayList<View>();
int count = l.getChildCount();
for (int i = 0; i < count; i++) {
View v = l.getChildAt(i);
if (v != null && v.getTag() != null
&& v.getTag().toString().equals("dynamicView")) {
removeViews.add(v);
}
}
for (View v : removeViews) {
l.removeView(v);
}
Please notice the v.getTag() != null && v.getTag().toString().equals("dynamicView") portion. You don't have to do it this way, however, this would be an easy way to differentiate between a view you added and a view that was statically created.
Edit in order for this to work when you create the view you need to call view.setTag("dynamicView"); of course