SetVisibility doesn't work? - android

I'm new to developing with android. I have a grid contained in a LinearLayout and each item which makes up the grid is a button. I want this LinearLayout to be invisible when the user pushes any of these buttons.
This is my 'home' layout shell:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView/>
<LinearLayout> //<-- this is the layout I want to hide
<TextView/>
<GridView/>
</LinearLayout>
</LinearLayout>
And this is the onClick method which I've set up in MyArrayAdapter (used to inflate buttons)
#Override
public void onClick(View v) {
View convertView = activity.getLayoutInflater().inflate(R.layout.layout_home, null);
LinearLayout ll_options = (LinearLayout) convertView.findViewById(R.id.ll_options);
ll_options.setVisibility(View.INVISIBLE);
}
I think it should work but when I test it, nothing happens.
I found a similar question but it doesn't solve my problem.

Why are you inflating a layout here?:
View convertView = activity.getLayoutInflater().inflate(R.layout.layout_home, null);
Just do:
View v = activity.findViewById(R.id.ll_options);
v.setVisibility(View.INVISIBLE);

You create a new view which is not in the visible view hierarchy until you add it there, and then you hide that. So you hide something invisible.
Instead, try:
#Override
public void onClick(View v) {
findViewById(R.id.ll_options).setVisibility(View.INVISIBLE);
}
which should IMO work. It searches for the ll_options view inside the visible (global) view hierarchy of your activity and hides that.

EDIT:
Where is your button? Is it in the same layout-file?
You inflate a new layout and hide the LinearLayout there, but this new layout is never used. Be sure you have access to the contentView in your listener.

Related

View is in the last position of parent, but still being blocked

What I want to do
In a BottomSheetDialogFragment, I want to inflate a view that always stick at the bottom of the screen, no matter what state (collapsed / expanded) the BottomSheetBehavior is in.
What I have done
In a subclass of BottomSheetDialogFragment, I inflate a view from XML and add it as a child of CoordinatorLayout (which is BottomSheetDialogFragment's parent's parent):
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupBottomBar(getView());
}
private void setupBottomBar (View rootView) {
CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
parentView.addView(LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false), -1);
}
The code runs without error.
And when I use Layout Inspector to look at the View hierarchy, the view structure is also correct:
You can also download the layout inspector result here, and open it using your own Android Studio.
The problem
However, even though it is inserted as the last child of the CoordinatorLayout, it is still being blocked by the BottomSheetDialogFragment.
When I slowly scroll the BottomSheetDialogFragemnt downwards (from collapsed state to hidden state), I can finally see the view that I want to inflate behind the fragment.
Why is this happening?
The answer
As #GoodDev pointed out correctly, it is because the root view (design_bottom_sheet) has been set a Z translation by BottomSheetDialog.
This provides an important information that - not only sequence in a View hierarchy will determine its visibility, but also its Z translation.
The best way is to get the Z value of design_bottom_sheet and set it to the bottom bar layout.
private void setupBottomBar (View rootView) {
CoordinatorLayout parentView = (CoordinatorLayout) (rootView.getParent().getParent());
View barView = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
ViewCompat.setTranslationZ(barView, ViewCompat.getZ((View)rootView.getParent()));
parentView.addView(barView, -1);
}
EDIT 2
Ok, now I see your requirement, try this one:
private void setupBottomBar (View rootView) {
CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
View view = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
// using TranslationZ to put the view on top of bottom sheet layout
view.setTranslationZ(100);
parentView.addView(view, -1);
}
EDIT:
OK, I check your layout and check the BottomSheetDialogFragment source code, found the reason:
In BottomSheetDialogFragment using BottomSheetDialog dialog, the method setContentView in BottomSheetDialog using wrapInBottomSheet to put the content view in R.id.design_bottom_sheet layout. So you need override the BottomSheetDialogFragment's public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) to fix your problem.
Or, change your setupBottomBar method to:
private void setupBottomBar (View rootView) {
FrameLayout frame = (FrameLayout)rootView.getParent();
frame.addView(LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, frame, false), -1);
}
and in your item_selection_bar layout file, change height and layout_gravity:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content">
BottomSheetDialogFragment doc says: Modal bottom sheet. This is a version of DialogFragment that shows a bottom sheet using BottomSheetDialog instead of a floating dialog.
So the BottomSheetDialogFragment is a Dialog, Dialog is a floating view, so will cover the Activity content when BottomSheetDialogFragment is showing.
#goodev has give a nice answer.
Your problem
View's Z position causes this problem. Although the TextView is the last position you still can not see it.
How to solve
You can set design_sheet_bottom's Z to TextView.
private void setupBottomBar (View rootView) {
CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
View view = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
view.setZ(((View)rootView.getParent()).getZ());
parentView.addView(view, -1);
}
And I think above way is very boring, can you put your two view RecyclerView and TextView into a layout ? Then you can inflate theme together in onCreateView() method.

findViewById() returns null for an inflated layout

I have an Activity and its layout. Now I need to add a LinearLayout from another layout, menu_layout.xml.
LayoutInflater inflater;
inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.menu_layout, null);
After this, findViewById() returns null. Is there is any solution for that?
Note: I can't put both XML in one place, and using <include> also is not working.
Explanation
When you inflate a layout, the layout is not in the UI yet, meaning the user will not be able to see it until it's been added. To do this, you must get a hold of a ViewGroup (LinearLayout,RelativeLayout,etc) and add the inflated View to it. Once they're added, you can work on them as you would with any other views including the findViewById method, adding listeners, changing properties, etc
Code
//Inside onCreate for example
setContentView(R.layout.main); //Sets the content of your activity
View otherLayout = LayoutInflater.from(this).inflate(R.layout.other,null);
//You can access them here, before adding `otherLayout` to your activity
TextView example = (TextView) otherLayout.findViewById(R.id.exampleTextView);
//This container needs to be inside main.xml
LinearLayout container = (LinearLayout)findViewById(R.id.container);
//Add the inflated view to the container
container.addView(otherLayout);
//Or access them once they're added
TextView example2 = (TextView) findViewById(R.id.exampleTextView);
//For example, adding a listener to the new layout
otherLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Your thing
}
});
Assuming
main.xml contains a LinearLayout with the id container
other.xml is a layout file in your project
other.xml contains a TextView with the id exampleTextView
Try using
layoutObject.findViewById();

Click Listener on the Whole Layout

I've an activity and inside it a list fragment. In case I receive no elements for the list i'd like to add an onclick listener on the whole layout to retry the request.
Activity layout relative_browse:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/relative_browse"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
Then inside the onCreateView of the fragment i inflate fragment_list_categoriers.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_list_categories"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/gray"
android:dividerHeight="1dp"
android:listSelector="#android:color/transparent" >
</ListView>
</RelativeLayout>
I tried to add the onclick listener on the empty list inside onActivityCreated, but it doesn't work:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View view = container.findViewById(R.id.fragment_list_categories);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("DEBUG", "Click!");
}
});
}
In particular I've no "Click" log, except for a tiny border of the screen on the left (it's like if the fragment_list_categories cover all the screen except some pixels).
What's the right way to do this?
EDIT: here my onCreateView and onClick method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.inflater = inflater;
View view = inflater.inflate(R.layout.fragment_list_categories,
container, false);
this.container = (ViewGroup) view;
view.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
Log.d("DEBUG", "Click!");
}
The first thing that pops out at me is that the ListView is taking up all the space.
Since you have its height set to match_parent, it will always occupy the entire parent's space. If the list is empty, this is probably not the desired behavior.
ListViews are sometimes weird about propagating clicks through to their parent views. When you click it, it's probably just dead-ending there instead of going up the chain. That would explain why you can get the clicks on the "border"; it's just the parent view's padding.
You may want to consider changing the ListView height to wrap_content. That way if it's empty, it won't take up space and you can get your clicks.
You may also want to try to detect if it's actually empty. If you have a couple entries that don't take up the full height of the parent, what is the expected behavior if the user clicks in the "empty" area? If that should trigger the retry as well, that's fine. If not, you need to enable/disable clicking based on that.
The very first thing you should do is in the onCreateView method instantiate your RelativeLayout as
View view = inflater.inflate("Your fragment layout", null);
RelativeLayout rl = (RelativeLayout) view.findViewByID("your relative layout's ID");
rl.setOnClickListener(this);
return view;
Then implement the OnClickListener and override the onClick method as,
#override
public void onClick(View v){
Log.d("Relative LAyout", String.valueOf(v));
}
In case you have already done the above then please post your onCreateView code.

LayoutInflater for using xml and View class

after I asked if I should use XML or a View class for my project you told me, that I should do everything possible in XML and use a class for the rest. You told me, that animating Sprites isn't possible with XML so I wanted to make a View Class. I got the tip to google "LayoutInflater" for this and I did.
There aren't many Informations about inflaters so I visited android's developers database and tried to find out how this works.
As far as I know now, you have to put something into the onCreate method of your main game activity (the setContentView has to be the mainXML).
So now I created a LinearLayout in my mainXML and called it "container" and made this being a ViewGroup called "parent".
Now I have created a global variable "private View view" and wrote this line:
view = LayoutInflater.from(getBaseContext()).inflate(new ViewClass(this),
null);
Thw Problem now is that u can't inflate a class like this and I think I'm doing this whole inflating thing wrong.
Do you have any tips and tricks for me for making it work to have a LinearLayout in my mainXML and being able to make the content from my View Class appear in it?
EDIT:
Got it to work without errors, but nothing happens if I start my game now.
Here is the code pls answer if u have any solutions:
super.onCreate(savedInstanceState);
// inflate mainXML->
View mainView = getLayoutInflater().inflate(R.layout.activity_game, null);
// find container->
LinearLayout container = (LinearLayout) mainView.findViewById(R.id.container);
// initialize your custom view->
view = new GameLayout(this);
// add your custom view to container->
container.addView(view);
setContentView(R.layout.activity_game);
And my GameLayout:
public GameLayout(Context context)
{
super(context);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color.BLACK);
}
There are two ways of going about this. I'll show you one of them. Do the following in your onCreate(Bundle) before calling setContentView(...):
// inflate mainXML
View mainView = getLayoutInflater().inflate(R.layout.mainXML, null);
// find container
LinearLayout container = (LinearLayout) mainView.findViewById(R.id.container);
// initialize your custom view
view = new ViewClass(this);
// add your custom view to container
container.addView(view);
Finally:
setContentView(mainView);
Alternatively, you can place your custom view inside mainXML:
<your.package.name.ViewClass
android:id="#+id/myCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent"
.... />

how to remove dynamically inflated views?

In a simple card game that i want to develop, I have three buttons: button1,button2 and button3. button1 creates two imageviews in a tablerow and displays the image. When button2 and/or button3 is clicked, it dynamically adds imageview on the tablerow through layout inflater. When game is over, I want user to click button1 and start things all over again. I am able to do that but the problem is, the imageviews that were previously displayed by clicking button2 and button3 also displays. I want them to be removed when button1 is clicked. How can I remove them on click of button1?
Please help me!
Just like you added views, you can remove them. Just call removeViewAt(int index) or removeView(View view) on the parent container to remove the view(s) you want.
Alternatively, if you foresee reusing them, you can just set their visibility to GONE. Then you could bring them back without the expense of inflating them again.
If you're letting the inflater automatically attach the inflated imageviews to the parent, then you'll have to keep track of the position of the added views. You can use getChildCount on the parent just before inflating to find the index of the next view that will be added.
you can use ViewGroup.removeView(View v);
something like this:
tblRow.removeView(button2);
here is how I add then remove a View 5 seconds later (in another context)
final LinearLayout linearLayout = context.getResources().getLayout(R.layout.activity_main)
LayoutInflater inflater = LayoutInflater.from(linearLayout.getContext());
final View details = inflater.inflate(R.layout.extra_details, linearLayout, false);
linearLayout.addView(details);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (linearLayout.findViewById(R.id.extra_details) != null){
linearLayout.removeView(details);
}
}
}, 5000);
the same use scenario is in the context of onClickListener.
Check more here https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
//add view
LayoutInflater inflater = (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
final View buttons = inflater.inflate(R.layout.activity, null );
addContentView(buttons, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//remove view
((ViewManager)buttons.getParent()).removeView(buttons);

Categories

Resources