8

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.

Nitish
  • 3,097
  • 13
  • 45
  • 80

2 Answers2

15

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.

Community
  • 1
  • 1
Nitish
  • 3,097
  • 13
  • 45
  • 80
-1

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;
    }
});
RuAware
  • 979
  • 1
  • 9
  • 26
  • This view will be visible from fragments. In order to intercept back button from fragment, I have to implement callback within activity, which will end up with lot of conditions and checks. I want to avoid this overhead, so I need to intercept back button within my custom view. It will be same as a dialog behaves on back button – Nitish Apr 01 '14 at 12:47
  • ok, can you handle the closing of the keyboard on backpress when using edittext. and requestfocus on the layout? – RuAware Apr 01 '14 at 12:50
  • I tried it earlier. When keyboard was visible, on pressing back button , the keyboard dismissed as desired, but logs in my overridden onKeyDown didn't showed up. – Nitish Apr 01 '14 at 12:53
  • http://stackoverflow.com/questions/5113437/get-back-key-event-on-edittext Use that, close keyboard and then focus on "this" – RuAware Apr 01 '14 at 12:58
  • How can I shift focus to my view after closing keyboard. Actually, I didn't understood the code. Why onKeyPreIme is beign used there? – Nitish Apr 01 '14 at 13:07
  • Have edited answer to use onkeylistener for one of your edittext, it might work. preIME has to be done i believe by extending the EditText class and may be over kill if this works – RuAware Apr 01 '14 at 13:27
  • Didn't worked, Android doesn't signals IME after closing the keyboard. I checked myself. – Nitish Apr 01 '14 at 13:29
  • So is that getting called? test with a log? maybe this is why you need preIME – RuAware Apr 01 '14 at 13:39
  • Just edited my post. It called up, but only after I pressed back button second time. – Nitish Apr 01 '14 at 13:40