Shake animation with Alert Dialog (if invalid info shake the edittext & do not dismiss)

梦想与她 提交于 2021-02-07 10:00:21

问题


So I have a dialog in which the user inputs data, here it is the user's age. So I would like that when/if the user leaves the edittext blank, the edittext will do the shake animation like that in the api demos. So far I cannot get the dialog from not dismissing when invalid info is inputed. Thanks.

mInflater = (LayoutInflater) Information.this.getSystemService(LAYOUT_INFLATER_SERVICE);
        mLayout = mInflater.inflate(R.layout.agedialog, null);

        mAgeEditText = (EditText) mLayout.findViewById(R.id.AgeEditText);
        mAgeResultTextView = (TextView) findViewById(R.id.AgeResultTextView);
        final Animation shake = AnimationUtils.loadAnimation(Information.this, R.anim.shake);

        mInputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        mInputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);

        new AlertDialog.Builder(Information.this).setView(mLayout).setTitle(R.string.EnterYourAge)
                .setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        mInputManager.hideSoftInputFromWindow(mAgeEditText.getWindowToken(), 0);
                        if (TextUtils.isEmpty(mAgeEditText.getText())) {
                            mAgeEditText.startAnimation(shake);
                            // here the dialog dismisses even if I call startAnimation
                        }
                        else {
                            HelperClass.getInstance().setAge(Integer.parseInt(mAgeEditText.getText().toString()));
                            mAgeResultTextView.setText(HelperClass.getInstance().getAge());
                        }
                    }
                }).setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        mInputManager.hideSoftInputFromWindow(mAgeEditText.getWindowToken(), 0);
                        dialog.cancel();
                    }
                }).show();

回答1:


Ok so I figured out the answer a long time after this was asked but just in case someone wants this I thought it was wise to go ahead and post the answer.

Basically this can NOT be done with the Alert Dialog, it has to do with the behavior when the button and negative buttons are clicked. However it can be done with a regular Dialog. You need a few animation xmls, and those can be found in the api demo's anim folder under res (The original java file is Animation1.java in api demos so you can check that out). I also made it so that the keyboard comes up ready for the user to type. You can rid of that by deleting all the inputmanager stuff. Anyway here's the code to the dialog.

public void showAgeDialog() {
    final Dialog dialog = new Dialog(Information.this);

    dialog.setContentView(R.layout.age_dialog);
    dialog.setTitle(R.string.InputAge);

    final EditText ageEditText = (EditText) dialog.findViewById(R.id.AgeEditText);

    inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);

    dialog.show();

    Button positive = (Button) dialog.findViewById(R.id.OkButton);
    Button negative = (Button) dialog.findViewById(R.id.CancelButton);

    positive.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            if (ageEditText.getText().toString().isEmpty()) {
                Animation shake = AnimationUtils.loadAnimation(Information.this, R.anim.shake);
                ageEditText.startAnimation(shake);
                Toast.makeText(Information.this, "Please enter an age", Toast.LENGTH_SHORT).show();
            }
            else {
                database.updateAge(Integer.parseInt(ageEditText.getText().toString()));
                inputManager.hideSoftInputFromWindow(ageEditText.getWindowToken(), 0);
                dialog.dismiss();
            }
        }
    });

    negative.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            inputManager.hideSoftInputFromWindow(ageEditText.getWindowToken(), 0);
            dialog.dismiss();
        }
    });
}

Here is the code to my layout. I made this dialog look exactly like an Alert Dialog with the Ok and Cancel buttons along with the gray background.

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/AgeEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="18dp"
        android:layout_marginLeft="100dp"
        android:layout_marginRight="100dp"
        android:hint="@string/Years"
        android:inputType="number"
        android:maxLength="2"
        android:textSize="18sp" >
    </EditText>

    <LinearLayout
        style="@android:style/ButtonBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/OkButton"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/Ok" />

        <Button
            android:id="@+id/CancelButton"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/Cancel" />
    </LinearLayout>

</LinearLayout>



回答2:


An extra little summer love story:

If you want to shake the entire AlertDialog, not only the EditText you can do something like this in your dialog fragment:

(NOTE! I have, for the sake of clarity, omitted any sanity checks, like null validation on context's and window's in the example code)

public Dialog onCreateDialog(Bundle savedInstanceState) {

    // Create the alert dialog as usual.
    AlertDialog shakyAlertDialog = new AlertDialog.Builder(getContext())
            .setTitle(R.string.title)
            .setMessage(R.string.message)    // Optional
            .setView(R.layout.input)         // This one holds your EditText
            .setNegativeButton(R.string.cancel, null)
            .setPositiveButton(R.string.ok, null)
            .show();

    // Get hold of the edit text we want to validate on.
    EditText input = shakyAlertDialog.findViewById(R.id.age_input);

    // Replace the "OK" button's click listener. As discussed in previous
    // answers this will replace the auto-dismiss behavior.
    shakyAlertDialog
            .getButton(DialogInterface.BUTTON_POSITIVE)
            .setOnClickListener(view -> {
                if (input.getText().isEmpty()) {
                    // This is the gold. This is how we shake the entire
                    // AlertDialog, not only the EditText.
                    shakyAlertDialog
                            .getWindow()
                            .getDecorView()
                            .animate()
                            .translationX(16f)
                            .setInterpolator(new CycleInterpolator(7f))
                } else {
                    // Do something with the input, but don't
                    // forget to manually dismiss the dialog.
                    shakyAlertDialog.dismiss()
                }
            });

    return shakyAlertDialog;
}



回答3:


It is definitively possible to implement OPs request with AlertDialog. A bit of tweaking is necessary, though.

AlertDialog will register its own OnClickListener on the buttons you create with the builder. Those handlers will delegate to your registered listener before dismissing the dialog.

The solution to circumvent this default behavior is to register your own handler immediately after the call to show() and thereby override the dialog's own listeners:

mLayout = mInflater.inflate(R.layout.agedialog, null);
mAgeEditText = (EditText) mLayout.findViewById(R.id.AgeEditText);
mAgeResultTextView = (TextView) findViewById(R.id.AgeResultTextView);

Animation shake = AnimationUtils.loadAnimation(Information.this, R.anim.shake);

// create dialog with buttons but without registering click listeners
AlertDialog dialog = new AlertDialog.Builder(Information.this)
    .setView(mLayout)
    .setTitle(R.string.EnterYourAge)
    .setPositiveButton(R.string.OK, null) // only declare button, add listener later
    .setNegativeButton(R.string.Cancel, null) // dito
    .create();

// define click listeners for ok and cancel
OnClickListener okListener = new OnClickListener() {
    public void onClick(View button) {
        mInputManager.hideSoftInputFromWindow(mAgeEditText.getWindowToken(), 0);
        if (TextUtils.isEmpty(mAgeEditText.getText())) {
            // input not valid -> shake
            mAgeEditText.startAnimation(shake);
        }
        else {
            HelperClass.getInstance().setAge(Integer.parseInt(mAgeEditText.getText().toString()));
            mAgeResultTextView.setText(HelperClass.getInstance().getAge());
            dialog.dismiss(); // close dialog, since input is valid
        }
    }
};
OnClickListener cancelListener = ...

// show dialog and immediately register our own listeners afterwards
dialog.show();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(okListener);
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(cancelListener);


来源:https://stackoverflow.com/questions/5577608/shake-animation-with-alert-dialog-if-invalid-info-shake-the-edittext-do-not-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!