I am using Relative Layout
and many buttons in it with TextViews etc.I want to make all of them not clickable
unless some event happens.
Problem : same as original question, but different use case. i want to progressBar widget which in container with transparent background colors. i want to disable all clicks on other items which comes under my transparent background color .
solution : just set your container clickable in my case Relative layout, it can any other layout too, keep your layout clickable true, until you want according to condition in my case till api call completed. after it simply set your parent clickable false.
android xml
<RelativeLayout
android:id="@+id/rl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- the children views begins -->
...
<!-- the children views ends -->
</RelativeLayout>
Java:
rl_parent.setClickable(true); // when to disable all clicks of children view
rl_parent.setClickable(false); // when to enable all clicks of children view
When you say click do you actually mean touch? Touch events are done element by element. They're first sent to the top level, which says if it handled it and if it didn't it goes onto each children of the view.
When a touch event is created, the onTouch
method of view in the chain is called, if any of these return true (true meaning "I handled this!") it stops going down to the children.
To make your relativelayout block touches and clicks for all of its children you simply need to set the onTouchListener, like this:
YOUR_RELATIVE_LAYOUT.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// ignore all touch events
return true;
}
});
This will ignore all touch events happening on the relative layout (and all of its children) which includes simple touch down then release events (called clicks).
You can use following function to find all the child view and cancel click.
public void setClickable(View view) {
if (view != null) {
view.setClickable(false);
if (view instanceof ViewGroup) {
ViewGroup vg = ((ViewGroup) view);
for (int i = 0; i < vg.getChildCount(); i++) {
setClickable(vg.getChildAt(i));
}
}
}
}
As an alternative way, you can make clickable ViewGroup with children views via FrameLayout instead of RelativeLayout. Just position your child views in FrameLayout using paddings and gravity, make FrameLayout clickable, and all children views non-clickable:
<FrameLayout
android:layout_width="51dp"
android:layout_height="59dp"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:onClick="@{() -> activity.onClick()}"
android:padding="5dp">
<android.support.v7.widget.AppCompatImageButton
android:layout_width="wrap_content"
android:layout_height="29dp"
android:layout_gravity="center"
android:clickable="false"
app:srcCompat="@drawable/ic_back" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:clickable="false"
android:text="@string/back" />
</FrameLayout>
If Butterknife library is used, the views can be grouped and the functionality can be done on the group. Refer http://jakewharton.github.io/butterknife/,
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
The apply method allows you to act on all the views in a list at once.
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
Action and Setter interfaces allow specifying simple behavior.
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};
For eg., if the textviews are grouped, you could do
static final ButterKnife.Setter<TextView, Boolean> ENABLED = new ButterKnife.Setter<TextView, Boolean>() {
@Override public void set(TextView view, Boolean value, int index) {
view.setClickable(value);
view.setLongClickable(value);
if(value){
view.setTextColor(color);
} else {
view.setTextColor(color);
}
}
};
A very simple and full-proof way to do it is to create a sub class and override onInterceptTouchEvent
:
public class MyRelativeLayout extends RelativeLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// true if you do not want the children to be clickable.
return mShouldInterceptAllTouch;
}
}
No need to call any of the children's methods.
You can still call setOnClickListener
on your myRelativeLayout
object. Also, you can use the class in XMLs as if you were using a RelativeLayout