Search code examples
androidonclicklistener

How can I fire Onclick event programmatically?


I have a custom view with 2 linear layouts: the first is the view's header and the second is the the details view.

In the custom view, the OnClickListener of the header Linearlayout is already defined: when it fires, it collapses/expandes the second linearlayout.

What I want to do is to add more functionalities to my header's OnClickListener event (i.e.: collapse/expand the second layout and show a Toast).

I can't modify the source code of the custom view. I tried to set a new OnClickListener but it hides the initial event (collapse/expand).

How should I implement this?

The source code of My Custom View:

public class ExpandoLayout extends ViewGroup
{
    /* some declarations */
    private Linearlayout header;
    private linearlayout footer;

    /* some code */
    @override
    protected void onFinishInflate() {
    header= new LinearLayout(context);
    header.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                toggleExpand();
            }
        });
    }
}

What I want to do is to add some code to the already defined OnClickListener event in my activity. Something like that:

public class myActivity extends Activity {
private Linearlayout myCustomView;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.rsdetail);
    myCustomView= (MyCustomView) findViewById(R.id.expanded);

    myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            if(v instanceof LinearLayout)
            {
                v.performClick();

                Toast.makeText(getActivity(), "ExpandoOnClickListener", 2000).show();
            }
        }
    });
}

Solution

  • Simple solution would be to get original OnClickListener and then fire it in new one:

    final OnClickListener preDefinedListener = myCustomView.getChildAt(0).getOnClickListner();
    
    myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            if(v instanceof LinearLayout)
            {
                preDefinedListener.onClick(v); // calls default (defined by MyCustomView)
    
                Toast.makeText(getActivity(), "ExpandoOnClickListener", 2000).show();
            }
        }
    });
    

    Sadly, View does not have getOnClickListner(), but I guess you can use reflection to get it. It is stored in the field mOnClickListener (source).

    This is how you can get OnClickListener defined for your layout:

    OnClickListener tmpOnClickListener = null;
    try {
        Class<View> cls = (Class<View>) Class.forName("android.view.View");
        Field fld = cls.getDeclaredField("mOnClickListener");
        fld.setAccessible(true); // because it is protected
    
        tmpOnClickListener = (OnClickListener) fld.get(myCustomView.getChildAt(0));
    
        fld.setAccessible(false); // restore it's original property
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } 
    
    final OnClickListener preDefinedListener = tmpOnClickListener;
    
    if (preDefinedListener != null) {
        myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View paramView) {
                preDefinedListener.onClick(paramView);
    
                Toast.makeText(getActivity(), "ExpandoOnClickListener", Toast.LENGTH_LONG).show();
            }
    });
    

    I didn't really bother to handle all exception correctly, but it's enough to get the idea. It might look messy, but it's actually just 5 lines of new code to solve your problem.