web-dev-qa-db-fra.com

Contrainte de mode de saisie logicielle de fenêtre

Auparavant, il n'y avait pas de problème avec le mode de saisie logicielle, mais après avoir inclus ConstraintLayout, le contenu du fragment ne remonte pas lorsque le clavier apparaît.

Manifeste

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="ru.pinspb.pinsupport">

    <uses-feature
        Android:name="Android.software.leanback"
        Android:required="false" />

    <uses-permission Android:name="Android.permission.INTERNET" />
    <uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission Android:name="Android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission Android:name="Android.permission.GET_ACCOUNTS" />
    <uses-permission Android:name="Android.permission.WAKE_LOCK" />
    <uses-permission Android:name="com.google.Android.c2dm.permission.RECEIVE" />

    <permission
        Android:name="ru.pinspb.pinsupport.permission.C2D_MESSAGE"
        Android:protectionLevel="signature" />

    <uses-permission Android:name="ru.pinspb.pinsupport.permission.C2D_MESSAGE" />
    <uses-permission Android:name="Android.permission.READ_PROFILE" />
    <uses-permission Android:name="Android.permission.READ_CONTACTS" />

    <application
        Android:name=".PinApp"
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:supportsRtl="true"
        Android:theme="@style/AppTheme.NoActionBar">
        <activity
            Android:name=".auth.ui.HomeActivity"
            Android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />

                <category Android:name="Android.intent.category.LAUNCHER" />
                <category Android:name="Android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            Android:name=".front.ui.FrontActivity"
            Android:launchMode="singleTop" />
        <activity
            Android:name=".chats.ui.InitChatActivity"
            Android:launchMode="singleTop"
            Android:windowSoftInputMode="stateHidden" />
    </application>

</manifest>

Fragment

public class AuthFragment extends Fragment implements ValidationListener {

    private static final String TAG = AuthFragment.class.toString();
    // UI references.
    @NotEmpty @Email @BindView(R.id.email) EditText email;
    @NotEmpty @BindView(R.id.password) EditText password;
    @BindView(R.id.auth_sign_in) Button signIn;
    @BindView(R.id.remember_me) CheckBox remember;
    @BindView(R.id.forgot) TextView forgot;
    @BindView(R.id.error) TextView errorField;
    @Inject @ApplicationContext
    Context context;
    private Validator validator;
    private onAuthenticateEventListener authenticatableEventListener;
    private String error = Constants.EMPTY_STRING;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            authenticatableEventListener = (onAuthenticateEventListener) activity;
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View render = inflater.inflate(R.layout.fragment_auth, container, false);
        ButterKnife.bind(this, render);

        final View activityRootView = render.findViewById(R.id.activity_root);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
            if (heightDiff > Helper.dpToPx(container.getContext(), 200)) { // if more than 200 dp, it's probably a keyboard...
                Log.d(TAG, "heightDiff: " + heightDiff);
            }
        });

        return render;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        errorField.setText(this.error);

        if(this.error.equals(Constants.EMPTY_STRING)) {
            errorField.setVisibility(View.GONE);
        } else {
            errorField.setVisibility(View.VISIBLE);
        }

        // Set up the login form.
        password.setOnEditorActionListener((textView, id, keyEvent) -> {
            if (id == R.id.login || id == EditorInfo.IME_NULL) {
                attemptLogin();
                return true;
            }
            return false;
        });

        validator = new Validator(this);
        validator.setValidationListener(this);

        signIn.setOnClickListener(v -> validator.validate());
    }

    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (invalid email, missing fields, etc.), the
     * errors are presented and no actual login attempt is made.
     */
    private void attemptLogin() {

        // Store values at the time of the login attempt.
        String email = this.email.getText().toString();
        String password = this.password.getText().toString();

        Bundle bundle = new Bundle();
        bundle.putString("email", email);
        bundle.putString("password", password);

        authenticatableEventListener.sendAuthRequest(bundle);
    }

    @Override
    public void onValidationSucceeded() {
        attemptLogin();
    }

    @Override
    public void onValidationFailed(List<ValidationError> errors) {
        for (ValidationError error : errors) {
            Log.d(TAG, "onValidationFailed: " + error.getCollatedErrorMessage(context));
            View view = error.getView();
            String message = error.getCollatedErrorMessage(context);

            // Display error messages ;)
            if (view instanceof EditText) {
                ((EditText) view).setError(message);
            } else {
                Toast.makeText(context, message, Toast.LENGTH_LONG).show();
            }
        }
    }

    public void setErrors(String text) {
        this.error = text;
    }

    public interface onAuthenticateEventListener {
        void sendAuthRequest(Bundle params);
        void showErrors(String error);
    }
}

Disposition

<Android.support.constraint.ConstraintLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:gravity="center_horizontal"
    Android:orientation="vertical"
    Android:background="@color/bg"
    Android:id="@+id/activity_root">

    <!-- Login progress -->
    <ProgressBar
        Android:id="@+id/login_progress"
        style="?android:attr/progressBarStyleLarge"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:visibility="gone"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintTop_toTopOf="@+id/activity_root"
        tools:layout_constraintTop_creator="1"
        app:layout_constraintRight_toLeftOf="@+id/activity_root"
        tools:layout_constraintRight_creator="1"
        app:layout_constraintBottom_toTopOf="@+id/activity_root"
        tools:layout_constraintBottom_creator="1" />

    <ImageView
        Android:layout_width="120dp"
        Android:layout_height="80dp"
        Android:id="@+id/logo"
        app:srcCompat="@drawable/logo_pin_support"
        Android:contentDescription="@string/contentDiscription"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintTop_toTopOf="@+id/activity_root"
        Android:layout_marginTop="56dp"
        tools:layout_constraintTop_creator="1"
        app:layout_constraintRight_toRightOf="@+id/activity_root"
        tools:layout_constraintRight_creator="1" />

    <EditText
        Android:id="@+id/email"
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        Android:hint="@string/auth.email"
        Android:inputType="textEmailAddress"
        Android:maxLines="1"
        Android:drawablePadding="10dp"
        Android:paddingTop="20dp"
        Android:paddingBottom="20dp"
        Android:textSize="@dimen/auth.sizes"
        Android:autoLink="none"
        Android:focusableInTouchMode="true"
        tools:ignore="RtlHardcoded"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        Android:layout_marginStart="16dp"
        app:layout_constraintTop_toBottomOf="@+id/error"
        Android:layout_marginTop="8dp"
        app:layout_constraintRight_toRightOf="@+id/activity_root"
        Android:layout_marginEnd="16dp"
        app:layout_constraintHorizontal_bias="0.56" />

    <EditText
        Android:id="@+id/password"
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        Android:hint="@string/auth.password"
        Android:imeActionId="@+id/login"
        Android:imeOptions="actionUnspecified"
        Android:inputType="textPassword"
        Android:maxLines="1"
        Android:drawablePadding="10dp"
        Android:textSize="@dimen/auth.sizes"
        Android:paddingTop="20dp"
        Android:paddingBottom="20dp"
        tools:ignore="MissingConstraints,RtlHardcoded"
        app:layout_constraintLeft_toLeftOf="@+id/email"
        app:layout_constraintTop_toBottomOf="@+id/email"
        app:layout_constraintRight_toRightOf="@+id/email"
        app:layout_constraintHorizontal_bias="0.0" />

    <TextView
        Android:text="@string/auth.title"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:textSize="27sp"
        Android:textColor="@color/greyish_brown"
        Android:id="@+id/textView"
        tools:ignore="MissingConstraints"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        Android:layout_marginStart="16dp"
        app:layout_constraintTop_toBottomOf="@+id/logo"
        Android:layout_marginTop="24dp"
        app:layout_constraintRight_toRightOf="@+id/activity_root"
        Android:layout_marginEnd="16dp" />

    <CheckBox
        Android:text="@string/auth.remember"
        Android:layout_width="0dp"
        Android:layout_height="32dp"
        Android:id="@+id/remember_me"
        style="@Android:style/Widget.Holo.Light.CompoundButton.CheckBox"
        Android:checked="true"
        Android:textSize="@dimen/auth.sizes"
        Android:textColor="@color/warm_grey"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        Android:layout_marginStart="16dp"
        app:layout_constraintTop_toBottomOf="@+id/password"
        Android:layout_marginTop="27dp"
        app:layout_constraintRight_toRightOf="@+id/activity_root"
        Android:layout_marginEnd="16dp"
        app:layout_constraintHorizontal_bias="0.0" />

    <Button
        Android:text="@string/auth.submit"
        Android:layout_width="152dp"
        Android:layout_height="51dp"
        Android:id="@+id/auth_sign_in"
        Android:background="@drawable/round_button"
        tools:ignore="MissingConstraints"
        Android:textColor="@color/white"
        Android:textSize="@dimen/auth.sizes"
        app:layout_constraintLeft_toLeftOf="@+id/activity_root"
        Android:layout_marginStart="16dp"
        app:layout_constraintTop_toBottomOf="@+id/remember_me"
        Android:layout_marginTop="46dp"
        app:layout_constraintRight_toRightOf="@+id/activity_root"
        Android:layout_marginEnd="16dp" />

    <TextView
        Android:text="@string/auth.forgot"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:id="@+id/forgot"
        Android:textColor="@color/pinkish_grey"
        app:layout_constraintLeft_toLeftOf="@+id/auth_sign_in"
        app:layout_constraintTop_toBottomOf="@+id/auth_sign_in"
        Android:layout_marginTop="16dp"
        app:layout_constraintRight_toRightOf="@+id/auth_sign_in" />

    <TextView
        Android:text="error"
        Android:layout_width="wrap_content"
        Android:layout_height="16dp"
        Android:id="@+id/error"
        Android:textColor="@color/lipstick"
        Android:visibility="gone"
        app:layout_constraintLeft_toLeftOf="@+id/textView"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        Android:layout_marginTop="16dp"
        app:layout_constraintRight_toRightOf="@+id/textView" />
</Android.support.constraint.ConstraintLayout>

Voici l'image pour comprendre:

enter image description here

Comment puis-je comprendre ce qui se passe? J'ai déjà utilisé ViewTreeObserver.

U.P.D.

Mon but est

enter image description here

Je m'attendais à ce que le contenu remonte lorsque le clavier apparaît, mais le clavier le chevauche à la place.

17
Scrobot

Tout fonctionne réellement comme prévu avec la façon dont votre mise en page est construite - les marges sont des distances fixes, donc votre interface utilisateur est tout simplement trop grande pour le petit écran. Vous auriez besoin de modifier votre mise en page pour mieux l'adapter à une petite mise en page - soit en marquant les vues inutiles (par exemple le logo) comme disparues (ConstraintLayout considérera les vues "disparues" comme réduites à un seul point, par essence - donc la mise en page reste fonctionne) ou modifiez certaines dimensions des marges en une valeur plus petite.

La manière habituelle de construire ceci est d'utiliser contraintes de biais ou directives , au lieu de marges dures. L'utilisation de biais ou de directives (en mode pourcentage) vous permettrait d'avoir un comportement semblable à un "ressort" pour mieux réagir aux changements de dimension. Généralement, une mise en page sera un mélange de marges dures et de biais/directives.

Pour résumer, vos options sont les suivantes:

  • modifier la mise en page pour utiliser les contraintes de biais/directives (pourcentage) pour avoir une mise en page plus réactive
  • marquer certaines vues comme GONE lors de la détection du clavier
  • changer certaines autres valeurs à la volée (taille de police, valeurs de marge ...)
  • ou créez un autre fichier de mise en page pour gérer ce cas
13
Nicolas Roard

Je ne sais pas dans quelle activité se trouve votre fragment, mais s'il se trouve par exemple dans InitChatActivity, ajoutez simplement adjustResize à votre manifeste et encapsulez votre ConstraintLayout dans ScrollView ou NestedScrollView:

Android:windowSoftInputMode="stateHidden|adjustResize"
6
r1m

J'ai rencontré le même problème avec vous, nous avons déclaré Android:windowSoftInputMode="stateAlwaysHidden|adjustResize" dans le AndroidManifest.xml, mais en fait, l'application a montré les résultats comme adjustPan, le contenu est allé au-dessus du clavier virtuel. J'ai donc défini adjustResize par programme, avec succès résolu ce problème:

Ajoutez simplement cette ligne à votre onCreate:

getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
3
drakeet