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:
Comment puis-je comprendre ce qui se passe? J'ai déjà utilisé ViewTreeObserver.
U.P.D.
Mon but est
Je m'attendais à ce que le contenu remonte lorsque le clavier apparaît, mais le clavier le chevauche à la place.
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:
GONE
lors de la détection du clavierJe 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"
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);