I noticed I was doing this in my code:
ResultButton = new Button( theActivity );
ButtonUtils.setButtonValues( ... );
((ViewGroup) (theActivity).findViewById( android.R.id.content )).addView( ResultButton );
ResultButton.setOnClickListener( new OnClickListener()
{
#Override
public void onClick(View arg0) {
doStuff();
((ViewGroup) (getActivity()).findViewById( android.R.id.content )).removeView( ResultButton );
}
});
That seems clearly wrong, to remove itself inside its OnClickListener. But what is the right way to deal with these things. Since there is no main method in an Android program I cannot just set a flag and then have it deal with it later.
You never really remove things? You just set them to invisible?
Inside your onClick implementation, the argument that you didn't rename corresponds to the view that triggered the event, you can call the parent of said view and ask it to remove the said child view.
ViewGroup parentView = (ViewGroup) view.getParent();
parentView.removeView(view);
To do this, rename arg0 to view, and you should be fine
Another option, as you mention is to just toggle its visibility, calling the setVisibility method, to either View.GONE or View.INVISIBLE depending on wether you want to to keep taking the screen space it was taking when visible or be completely gone, but since you asked to remove the view, the first option should suffice.
Related
In my app, I need to show and hide widgets like button and textview at a certain time.
and how I am doing is as the following:
private void hideviews() {
image.setVisibility(View.GONE); ///ImageView
title1.setVisibility(View.GONE);///TextView
title2.setVisibility(View.GONE);///TextView
title3.setVisibility(View.GONE);///TextView
title4.setVisibility(View.GONE);///TextView
title5.setVisibility(View.GONE);///TextView
}
private void showviews() {
image.setVisibility(View.VISIBLE);
title1.setVisibility(View.VISIBLE);///TextView
title2.setVisibility(View.VISIBLE);///TextView
title3.setVisibility(View.VISIBLE);///TextView
title4.setVisibility(View.VISIBLE);///TextView
title5.setVisibility(View.VISIBLE);///TextView
}
I don't think this is the correct way to do this.
Because I don't know how many widgets there will be.
Any guidance on how to correctly show widgets is really appreciated.
Get the reference to root layout, iterate through the childs, check if the view at certain index is instance of EditText(or View that you dont need to hide), if not hide it
RelativeLayout root = findViewById(R.id.root)
for(i=0,i<root.getChildCount()-1,i++){
if(! (root.getChildAt(i) instance of EditText)){
root.getChildAt(i).setVisibility(View.GONE)
}
}
Since you don't know how many testviews will be attached, then I believe that the best approach will be to:
get the reference of the parent view group (that contains all the
textviews),
loop through all the childs using getChildAt,
verify whether the object is an instance of TextView/ImageView and if so set its visibility according to your logic
Instead of hiding every widget separately hide the root layout.
RelativeLayout rootLayout;
rootLayout= (RelativeLayout) findViewById(R.id.root_layout);
and use something like this to control the visibility.
public void setLayoutInvisible() {
if (rootLayout.getVisibility() == View.VISIBLE) {
rootLayout.setVisibility(View.GONE);
}
}
public void setLayoutVisible() {
if (rootLayout.getVisibility() == View.GONE) {
rootLayout.setVisibility(View.VISIBLE);
}
}
Make an array of all the views that you want to show/hide:
View[] views = {image, title1, title2, title3, title4, title5};
and then use this to hide them:
for (View view : views) {
view.setVisibility(View.GONE);
}
and use this to show them:
for (View view : views) {
view.setVisibility(View.VISIBLE);
}
although you can combine the 2 code parts in a single procedure:
void fixViews(int state) {
for (View view : views) {
view.setVisibility(state);
}
}
and call it:
fixViews(View.GONE); or fixViews(View.VISIBLE);
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView1"
android:layout_alignParentTop="true"
android:text="#string/button1"
android:onClick="onClickButton"/>
public void onClickButton(View view){
TextView textview = (TextView) findViewById(R.id.textView1);
textview.setVisibility(View.VISIBLE);
}
That is the code that makes the text appear in the main activity interface when the button is pressed. What is the point of passing in an View object when you don't use it in the "onClickButton" method block? I am asking this because the app crashes if I leave out the parameter even when I am not using the view object in the code block.
You might have several buttons in your layout, and only one method in your activity's code. In such a situation, it becomes necessary to differentiate between different buttons.
That's where this can be used.
public void onClickButton(View view){
if(view.getId() == R.id.buttonSave){
// Do something
} else if(view.getId() == R.id.buttonCancel){
// Do something else
}
}
Although, you can bind different methods to different views, by having a method for each view type.
Yet another use case could be:
After clicking on the button, you want to modify the button itself, say, hide it, or change the label, then you obviously need a reference to the button.
what is the point of passing in an object view of type View when you don't use it in the "onClickButton" method block?
First of all, the Button Docs tell you to. Secondly, it can get used in the function. Since Buttons aren't the only Views which are clickable, having the View parameter allows you to check that View type to see what has been pressed and to perform other operations with it.
public void onClickButton(View view){
TextView textview = (TextView)view;
textview.setVisibility(View.VISIBLE);
}
This should work if you are passing a view directly to the method.
In my Android app there is a requirement that a number of UI elements should be disabled until a button click carryout. Can I disable all the UI elements in a layout by referring the layout without disable them one by one. Is it possible.Can some one help me.
You could disable all views recursively like this.
Just pass the layout as view to the method:
private void enableViews(View v, boolean enabled) {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0;i<vg.getChildCount();i++) {
enableViews(vg.getChildAt(i), enabled);
}
}
v.setEnabled(enabled);
}
Just run enableViews(view, false) to disable, or enableViews(view, true) to enable again.
use following attribute in your xml layout( as a example textView)
android:visibility="gone"
in button click event
myText.setVisible(myText.VISIBLE)
you can either use them one by one or you can put all invisible content in a single layout and hide the layout. then once you want to show them, just VISIBLE the layout. then all will display
need any more comment.. just comment.
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"
I have a layout which contains lots of images. What I have to do is when an image is clicked, I have to show its details. But I don't want to have onClickListeners for all the images. How can I achieve this?
You don't have to have different handlers for all the images. Instead use one handler for all the images. This would make your code cleaner, manageable and solve your problem too.
public void onCreate(Bundle bundle) {
//...
OnClickListener mHandler = new OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.img1:
//..
break;
case R.id.img2:
//....
break;
}
}
};
ImageButton btn1 = (ImageButton)findViewById(R.id.img1);
ImageButton btn2 = (ImageButton)findViewById(R.id.img2);
//...
btn1.SetOnClickListener(mHandler);
btn2.SetOnClickListener(mHandler);
//...
}
One Listener to rule them all.
Implement onClick() on an object, register it as listener
In onClick(), examine the View object passed as parameter to determine which of the images was clicked. You can do anything from getId() to casting it to (ImageView) and getting the actual image out.
Once you know which image was clicked, do what you will with it.
If you're looking to implement custom behavior for an ImageView (or whatever), and then have multiple instances of that type of view, you should subclass the ImageView and put your listener in there. Then you've got an encapsulated View that implements the custom behavior you want, and if you decide later that you want more or less or them, or to put them in another place, it's easy to move the View and its behavior without ripping apart your Activity.