Hiding linear layout on runtime in Android - android

I am having following layout
<merge>
<LinearLayout
android:id="#+id/ll_main"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
/>
<LinearLayout
android:id="#+id/ll_sub"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
/>
</merge>
What I want to do is to show/hide the ll_sub layout on runtime through setVisibility() but it is not working.
When I am setting android:visibility="gone" (also I had checked with invisible) from the xml of ll_sub then it is not displayed on the screen and this time when I use setVisibility() to show this layout on runtime, it is displayed but when I try to hide this layout once it is displayed then it is not hiding.
EDIT
I am trying to show/hide this linear layout on click of a button.
LinearLayout ll;
Button minimize;
int visibility=0;
#Override
public void onCreate(Bundle savedInstanceState)
{
ll=(LinearLayout)findViewById(R.id.ll_sub);
minimize=(Button)findViewById(R.id.minimize);
minimize.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
if(visibility==0)
{
visibility=2;
}
else
{
visibility=0;
}
ll.setVisibility(visibility);
}
});
}

It looks like you're setting the wrong constants for changing view visibility.
GONE == 8
INVISIBLE == 4
VISIBLE == 0
However, you should never rely on the actual values that Android happened to designate to represent their constants. Instead use the the values defined in the View class: View.VISIBLE, View.INVISIBLE, and View.GONE.
// snip...
if(visibility == View.VISIBLE)
{
visibility = View.GONE;
}
else
{
visibility = View.VISIBLE;
}
ll.setVisibility(visibility);
And don't forget to call invalidate() on the view :)

You should use the Constants provided by View
View.INVISBLE, View.VISIBLE, View.GONE
and also invalidate your View

Related

How to make the layout visible/gone?

I am working on an app using geolocation and I want to set a layout VISIBLE when close to a point and GONE when too far from the point.
This is my xml :
<LinearLayout
android:visibility="gone"
android:id="#+id/slidePane"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
Then I use the ID in the activity as usual :
declare it in the class attribute :
private LinearLayout slidepane;
set it in the onCreate() method :
slidepane = (LinearLayout) findViewById(R.id.slidePane);
And then I try to update it in onLocationChanged() method as follows :
if (InterestPoint.CalculationByDistance(location, new LatLng(47.247801, -1.551883)) < 0.03) {
Toast.makeText(MainActivity.mContext, "InterestPoint close", Toast.LENGTH_SHORT).show();
slidepane.setVisibility(View.VISIBLE);
} else {
slidepane.setVisibility(View.GONE);
}
So the condition is correct since the Toast appears but the layout does not become visible, why?
Thank you.
EDIT : I am using https://github.com/umano/AndroidSlidingUpPanel and try to set the visibility of the second child (the sliding panel). I didn't see anything in the documentation about visibility. I can still access the children of the LinearLayout but not the container itself (and especialy the visibility).
Replace this:
slidepane.setVisibility(View.VISIBLE);
with this:
runOnUiThread(new Runnable() {
#Override
public void run() {
slidepane.setVisibility(View.VISIBLE);
}
});
Make sure you set the visibility of view at the time of initialization.
#Override
protected void onCreate(Bundle savedInstanceState) {
........
slidepane = (LinearLayout) findViewById(R.id.slidePane);
slidepane.setVisibility(View.GONE);
.......
//onLocationChanged() add ->
if (InterestPoint.CalculationByDistance(location, new LatLng(47.247801, -1.551883)) < 0.03) {
Toast.makeText(MainActivity.mContext, "InterestPoint close", Toast.LENGTH_SHORT).show();
slidepane.setVisibility(View.VISIBLE);
} else {
slidepane.setVisibility(View.GONE);
}

How to disable user interaction while ProgressBar is visible in android?

I am using a custom ProgressBar. Now while a task is going on, I am showing the progress bar, but user can still interact with the views and controls.
How do I disable the user interaction on whole view just like a ProgressDialog does , when it is visible.
Do I need to use a transparent view on top of main view and show the progress bar on that view and hide that view once a task is completed.
Or just get the id of my parentView and set it disabled ? But then I won't be able to dim the background, just like what happens when a dialog appears on the view/Activity/Fragment. Right?
I just want to know the way to disallow the user from any interaction while the progressbar is visible.
Thanks
Your question: How to disable the user interaction while ProgressBar is visible in android?
To disable the user interaction you just need to add the following code
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
To get user interaction back you just need to add the following code
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Here is an example:
Note:I am giving you just an example to show how to disable or retain user interaction
Add a progress bar in your xml.Something like this
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar"
android:visibility="gone"/>
In MainActivity when a button pressed you show the progressbar and disable the user interaction.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProgressBar.setVisibility(View.VISIBLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
});
}
And when user backPressed you remove the progressbar again retain the user interaction.Something like this
#Override
public void onBackPressed() {
super.onBackPressed();
mProgressBar.setVisibility(View.GONE);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
If you want to add a feature of disable and greyed out display, you need to add in your xml layout file a linear layout that fills the parent. Set its background to #B0000000 and its visibilty to GONE. Then programmatically set its visibility to VISIBLE.
Hope this help!
I have fixed this issue by adding root layout to the ProgressBar.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clickable="true"
android:gravity="center"
android:visibility="gone"
android:id="#+id/progress">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
android:indeterminateTintMode="src_atop"
android:indeterminateTint="#color/primary"/>
</LinearLayout>
Made the root layout clickable
android:clickable="true"
NOTE: In my main view, I had RelativeLayout as root and have added above-mentioned code inside the root layout at the last position (last child).
Hope this helps!!
just set:
android:clickable="true"
in your xml
<ProgressBar...
Only this makes magic!
To extend (pun intended) on the accepted Answer :
When you use kotlin you can use extension functions. That way you have a quick and nice looking method for blocking and unblocking UI.
fun AppCompatActivity.blockInput() {
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.unblockInput() {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.blockInputForTask(task: () -> Unit) {
blockInput()
task.invoke()
unblockInput()
}
You can use the blocking and unblocking functions in your activity. Also, you can add more functionality like showing a Toast or something.
When using it in a custom view or any other view, you can simply cast the context to activity and use the functions.
Use blockInputForTask to surround simple linear tasks and blockInputand unblockInput when they are needed in different scopes.
You can use blockInputForTask like this:
blockInputForTask {
// Your lines of code
// Can be multiple lines
}
Use document default method progressbar.setCancelable(false)
Make a dialog with transparent background. The issue with getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); is that when app will go in background and come back user will be able to interact with UI components, a lot more handling. So for blocking UI make a transparent dialog and if you want to set time for hide/show. Do this in a runnable thread. So the solution will be
public class TransparentDialogHelper {
private Dialog overlayDialog;
#Inject
public TransparentDialogHelper() {
}
public void showDialog(Context context) {
if (AcmaUtility.isContextFinishing(context)) {
return;
}
if (overlayDialog == null) {
overlayDialog = new Dialog(context, android.R.style.Theme_Panel);
overlayDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
}
overlayDialog.show();
}
public void hideDialog() {
if (overlayDialog == null || AcmaUtility.isContextFinishing(overlayDialog.getContext())) {
return;
}
overlayDialog.cancel();
}
}
-------- Timer
Handler handler = new Handler();
handler.postDelayed( () -> {
view.hideProgress();
}, 2000);
Make your parent layout as Relative Layout & add this :
<RelativeLayout ... >
<other layout elements over which prog bar will appear>
<RelativeLayout android:id="#+id/rl_progress_bar"
android:layout_width="match_parent" android:clickable="true"
android:layout_height="match_parent" >
<ProgressBar android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
style="#android:style/Widget.DeviceDefault.ProgressBar"
android:theme="#style/AppTheme.MyProgressBar"
/>
</RelativeLayout>
If you have floating buttons in your UI, they still grab all the focus & remain clickable when the progress bar is visible. for this use : (when your prog bar is visible & re-enable them when you make your prog bar invisible/gone)
fb.setEnabled(false);

How to disable all buttons in a Layout?

The way app works is the following: App prompts 30 buttons to user and user may guess the right ones by tapping. When user taps some button all the buttons (say a view containing these buttons) should be locked while corresponding (right or wrong guess) animation is playing. Tapped button by itself should be disabled till the next round. After animation is finished all not tapped previously buttons (say a view containing these buttons) should be available again.
So I have a Layout which includes another layout with these 30 buttons:
...
<RelativeLayout
android:id="#+id/alphabetContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include layout="#layout/alphabet" />
</RelativeLayout>
...
Now I need to lock the buttons from being clicked and then unlock. So I tried:
...
private RelativeLayout alphabetPanel;
...
public void onCreate(){
...
alphabetPanel = (RelativeLayout) findViewById(R.id.alphabetContainer);
...
}
...
private void lockButtons(){
alphabetPanel.setEnabled(false);
}
but this doesn't lock buttons. I also tried:
alphabetPanel.setFocusable(false);
alphabetPanel.setClickable(false);
Doesn't help either. Seems like it all relies only to a layout by itself but not the views it contains.
Also I tried to add a fake layout to place it over layout with buttons by bringing it to the front. This is a workaround and its tricky cuz both layouts must be placed inside a RelativeLayout only:
...
blockingLayout = new RelativeLayout(this);
blockingLayout.setLayoutParams(alphabetPanel.getLayoutParams());
...
but this works very strange: somehow both layouts in this case appears and disappears every second or so or doesn't appear at all - I cant understand that at all cuz there is no setVisibility() method used in code!
The only one way left is to iterate every view (button) to make it disabled and than back.
Is there any other way?
UPDATE
Finally I had to add a "wall"-layout into the xml. Now by making it clickable and focusable it becomes a solution.
Try setting for each Button's xml definition
android:duplicateParentState="true"
I'm not sure, but I think it should make them not only to seem disabled, but also to act accordingly.
Hmm it surprises me that disabling the parent-layout doesn't work.. as far as i know it should.
Try fetching your included layout instead, and disable that.
Anyway, if all else fails you can always loop through the buttons themselves.
for(int i=0;i<relativeLayout.getChildCount();i++){
View child=relativeLayout.getChildAt(i);
//your processing....
child.setEnabled(false);
}
I used extension to lock and unlock the view
//lock
fun View.lock() {
isEnabled = false
isClickable = false}
//unlock
fun View.unlock() {
isEnabled = true
isClickable = true}
if you want to lock all children of the view group
//lock children of the view group
fun ViewGroup.lockAllChildren() {
views().forEach { it.lock() }}
//unlock children of the view group
fun ViewGroup.unlockAllChildren() {
views().forEach { it.unlock() }}
firstly define your button
Button bit = (Button)findViewById(R.id.but);
bit.setEnabled(false);
and set enabled false;
Java:-
public void disableButtons(Layout layout) {
// Get all touchable views
ArrayList<View> layoutButtons = layout.getTouchables();
// loop through them, if they are instances of Button, disable them.
for(View v : layoutButtons){
if( v instanceof Button ) {
((Button)v).setEnabled(false);
}
}
}
Kotlin:-
fun disableButtons(layout: Layout) {
// Get all touchable views
val layoutButtons: ArrayList<View> = layout.getTouchables()
// loop through them, if they are instances of Button, disable them.
for (v in layoutButtons) {
if (v is Button) {
(v as Button).setEnabled(false)
}
}
}
Retrieve all touchables views into an ArrayList, then loop through them and check if it is an instance of the Button or TextView or which ever you want, then disable it!
In case data binding is needed
import android.view.ViewGroup
import android.widget.Button
import androidx.core.view.children
import androidx.databinding.BindingAdapter
#BindingAdapter("disableButtons")
fun ViewGroup.setDisableButtons(disableButtons: Boolean) {
children.forEach {
(it as? Button)?.isEnabled = !disableButtons
}
}
Usage:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="#dimen/guideline"
app:disableButtons="#{vm.busy}">
....
</androidx.constraintlayout.widget.ConstraintLayout>
Might work in constraint layout . Use group widget and add all the button ids.
In the java code set enabled false for the group.
For disable all buttons in any nested layouts.
void DisableAllButtons( ViewGroup viewGroup ){
for( int i = 0; i < viewGroup.getChildCount(); i++ ){
if( viewGroup.getChildAt(i) instanceof ViewGroup ){
DisableAllButtons( (ViewGroup) viewGroup.getChildAt(i) );
}else if( viewGroup.getChildAt(i) instanceof Button ){
viewGroup.getChildAt(i).setEnabled( false );
}
}
}
write these two lines on your button declartion in XML
android:setEnabled="false"
android:clickable="false"

Android: How to propagate click event to LinearLayout childs and change their drawable

I would like to create a linear layout which would behave similarly to ImageButton.
<LinearLayout
android:id="#+id/container"
style="?WidgetHomeIconContainer">
<ImageView
android:id="#+id/icon"
style="?WidgetHomeIcon" />
<TextView
android:id="#+id/title"
style="?WidgetHomeLabel"
android:text="#string/title"
android:textAppearance="?attr/TextHomeLabel" />
</LinearLayout>
In styles of ImageView, TextView and LinearLayout, I set a selectors for all states.
Now:
when I click on ImageView (I tried it also with ImageButton) - it behaves correctly and the image is changed according the selector xml.
when I click on LinearLayout - the linear layout is clicked, but the the ImageView and TextView don't change it's drawable/appearance
So I would like to do the following. When I click on parent LinearLayout, I need to change all it's childs to pressed state.
I tried to add following code to LinearLayout onClickListener to propagate the click:
#Override
public void onClick(View v)
{
LinearLayout l = (LinearLayout) v;
for(int i = 0; i < l.getChildCount(); i++)
{
l.getChildAt(i).setClickable(true);
l.getChildAt(i).performClick();
}
}
But it still reamins the same. Thank you very much for any help.
Put
android:duplicateParentState="true"
in your ImageView and TextView..then the views get its drawable state (focused, pressed, etc.) from its direct parent rather than from itself.
Not only make for every child:
android:duplicateParentState="true"
But also additionally:
android:clickable="false"
This will prevent unexpected behaviour (or solution simply not working) if clickable child views are used.
SO Source
After having the same problem some months later, I found this solution:
private void setOnClickListeners() {
super.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onClick(v);
}
});
for (int index = 0; index < super.getChildCount(); index++) {
View view = super.getChildAt(index);
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onClick(v);
}
});
}
}
protected void onClick(View v) {
// something to do here...
}
In my case, no one of the other solutions works!
I finally had to use OnTouchListener as explained here, capturing the event when the user clicks in the parent view, and removing all childs OnClickListener.
So the idea is, delegate the click behavior to the parent, and notify the child that is really clicked, if you want to propagate the event. ¡¡That's what we are looking for!!
Then, we need to check which child has been clicked. You can find a reference here to know how it´s done. But the idea is basiclly getting the area of the child, and asking for who contains the clicked coordinates, to perform his action (or not).
At first, my child view failed to get click from parent. After investigating, what I need to do to make it work are:
remove click listener on child view
adding click listener on parent view
So, I don't need to add these on every children.
android:duplicateParentState="true"
android:clickable="false"
I only add duplicateParentState to one of my child view.
My child view is now listening to parent click event.

Android: swapping two overlapping views

Can anyone tell me what's wrong with this implementation? All I want to do here is have two overlapping views that swap places when you tap the screen. Unless I'm just using it wrong, View.bringToFront() does nothing?
Below is all the code in my app. Note that I added padding to the 'backView' just to make sure the two were actually overlapping. Indeed I could see both on the screen. While tapping the top view does indeed trigger the onClick method, nothing visibly changes in response to the calls to bringToFront.
public class MainActivity extends Activity implements OnClickListener {
private ImageView frontView;
private ImageView backView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
frontView = (ImageView) findViewById(com.example.R.id.FrontView);
backView = (ImageView) findViewById(com.example.R.id.BackView);
frontView.setOnClickListener(this);
backView.setOnClickListener(this);
backView.setPadding(10,0,0,0);
}
private boolean flag;
public void onClick(View v) {
if (!flag) {
backView.bringToFront();
}
else {
frontView.bringToFront();
}
flag = !flag;
}
}
and the corresponding layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/FrontView"
android:src="#drawable/front"
/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/BackView"
android:src="#drawable/back"
/>
</RelativeLayout>
Maybe it's the layout I'm using? I'm not sure... I've tried FrameLayout and LinearLayout as well.
I would try swapping content views instead of ImageViews.
Put each imageView in a different layout and then it is easy:
public void onClick(View v) {
if (!flag) {
setContentView(R.layout.main_front);
frontView = (ImageView) findViewById(com.example.R.id.FrontView);
frontView.setOnClickListener(this);
}
else {
setContentView(R.layout.main_back);
backView = (ImageView) findViewById(com.example.R.id.BackView);
backView.setOnClickListener(this);
}
flag = !flag;
}
There are a couple of Components that you can use that do this for you.
ViewAnimator, ViewFlipper and ViewSwitcher. You can set the animations you require etc and they hand the rest.
here's one example.
http://www.androidpeople.com/android-viewflipper-example/
Given your example, do you have to call invalidate() on the parent after you've called bringToFront() ?

Categories

Resources