Home » Android » Android: Handle Back button from custom view

Android: Handle Back button from custom view

Posted by: admin June 15, 2020 Leave a comment

Questions:

I had created a custom view for my app by extending RelativeLayout. It opens up as dialog, by dragging an ImageView. It has EditTexts and Buttons. I am overriding onKeyDown in my view as I need to intercept back button from this view. If custom view is visible, edittext has not gained focus, and if I press back button, the view will be dismissed, which is desired.

Problem arises, when edittext has gained focus, and keyboard is visible, on pressing back button, soft keyboard is dismissed, but if I press back button again, then instead of dismissing custom view, super.onKeyDown() is called and I exit from my app, where as desired feature is to dismiss the view after dismissal of soft keyboard. What am I doing wrong?

Below is my custom view code:

public class AddTransactionView extends RelativeLayout implements View.OnClickListener {
    private final String TAG = "AddTransactionView";

    private Context context;

    private ViewGroup parentView;

    private FriendsDAO mFriendsDAO;

    private AppPreference mAppPreference;

    private ImageLoader imageLoader;

    private DisplayImageOptions options;

    private CircularImageView friendsImage;

    private Button btnIOwe, btnTheyOwe;

    private EditText edtTransactionDesc, edtTransactionAmt;

    private RelativeLayout relAddTransaction;

    private int status;

    public AddTransactionView(Context context, View anchorView, int marginTop,
        ViewGroup parentView, FriendsDAO mFriendsDAO) {
        super(context);
        Log.e(TAG, "AddTransactionView constructor");
        this.context = context;
        this.parentView = parentView;
        this.mFriendsDAO = mFriendsDAO;
        doInitialization();
        LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.add_transaction_popup, this);

        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT);

        params.addRule(RelativeLayout.ABOVE, anchorView.getId());
        params.setMargins(0, marginTop, 0, 0);
        view.setLayoutParams(params);
        this.setFocusableInTouchMode(true);
        this.requestFocus();
        parentView.addView(this);
        initializeView(view, mFriendsDAO);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.e(TAG, "onKeyCodeDown");
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            Log.e(TAG, "onKeyCodeDown if");
            Log.e(TAG, "onKeyCodeDown else");
            dismiss();
            return true;
        } else {
            Log.e(TAG, "onKeyCodeDown default");
            return super.onKeyDown(keyCode, event);
        }
    }

    private void dismiss() {
        parentView.removeView(this);
    }
}

PS: I had not used dialog or popup window due to design limitation in my app.

Update 1

When keyboard is closed, the focus doesn’t shifts back to my custom view. I tried the suggested answer below, but I figured out, android does not sends IME events when keyboard is dismissed. Is there any other way to get focus back to my view after keyboard dismissal?

Update 2
Just Now, I found that onKeyListener of edittext fired up only, after I pressed back button second time, that is after dismissal of keyboard. That’s why the solution below, didn’t worked.

How to&Answers:

I finally solved my problem, the solution is to use dispatchKeyEventPreIme. Below is snippet from my actual code:

@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
    Log.e(TAG, "dispatchKeyEventPreIme(" + event + ")");
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        KeyEvent.DispatcherState state = getKeyDispatcherState();
        if (state != null) {
            Log.e(TAG, "dispatchKeyEventPreIme state != null");
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getRepeatCount() == 0) {
                Log.e(TAG, "dispatchKeyEventPreIme ACTION_DOWN");
                state.startTracking(event, this);
                return true;
            } else if (event.getAction() == KeyEvent.ACTION_UP
                    && !event.isCanceled() && state.isTracking(event)) {
                Log.e(TAG, "dispatchKeyEventPreIme ACTION_UP");
                if (edtTransactionAmt.hasFocus()
                        || edtTransactionDesc.hasFocus()) {
                    Log.e(TAG, "dispatchKeyEventPreIme edittext has focus");
                    AppUtils.hideSoftKeyboard(context, edtTransactionAmt);
                    edtTransactionAmt.clearFocus();
                    edtTransactionDesc.clearFocus();
                } else {
                    Log.e(TAG, "dispatchKeyEventPreIme dismiss view");
                    dismiss();
                }
                return true;
            }
        }
    }

    return super.dispatchKeyEventPreIme(event);
}

But the actual credit goes to this post.

Answer:

Can you not have onbackpress in your main activity with

if (myAddTransactionView.getVisibility == LinearLayout.VISIBLE) {
     myAddTransactionView.dismiss();
} else {
   Super.....

Or on your edit text

edtTransactionDesc.setOnKeyListener(new OnKeyListener()
{
    public boolean onKey(View v, int keyCode, KeyEvent event)
    {
        if (event.getAction() == KeyEvent.ACTION_DOWN)
        {
            //check if the right key was pressed
            if (keyCode == KeyEvent.KEYCODE_BACK)
            {
                InputMethodManager imm = (InputMethodManager)getSystemService(
                 Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(edtTransactionDesc.getWindowToken(), 0);
                AddTransactionView.this.requestFocus(); 
                return false;
            }
        }
        return true;
    }
});