我想在键盘出现时调整屏幕的一部分。
我要这个:
所以我只想要ListView调整大小,如果我选择EditText1或EditText2,我想看到两者。如果选择ET1我也需要看ET2。
现在我有这个XAML但是当键盘出现时我的所有屏幕都向上滚动,当我选择ET1时,ET2在键盘后面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_marginTop="10dp"
android:paddingBottom="10dp"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="@android:color/black"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ListView
android:background="@drawable/border_shadow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:importantForAccessibility="auto"
android:isScrollContainer="true"/>
</RelativeLayout >
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:layout_width="100dp"
android:singleLine="true"
android:layout_height="wrap_content"
android:textColor="@android:color/white" />
<AutoCompleteTextView
android:singleLine="true"
android:layout_width="100dp"
android:textColor="@android:color/white"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_marginTop="120dp"
android:layout_height="wrap_content">
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:shadowColor="#00000000"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:background="@drawable/button"
android:textColor="@android:color/white"
android:clickable="true"/>
<Button
android:layout_width="100dp"
android:layout_marginLeft="10dp"
android:layout_height="50dp"
android:shadowColor="#00000000"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:background="@drawable/button"
android:textColor="@android:color/white"
android:clickable="true"/>
</LinearLayout>
</LinearLayout>
我需要改变什么?
Create One class Name AlignLayoutDesign
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.widget.FrameLayout;
public class AlignLayoutDesign
{
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private Rect contentAreaOfWindowBounds = new Rect();
public AlignLayoutDesign(Activity activity)
{
FrameLayout content = activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent()
{
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious)
{
int heightDifference = 0;
if (heightDifference > (usableHeightNow /4))
{
// keyboard probably just became visible
frameLayoutParams.height = usableHeightNow - heightDifference;
}
else
{
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightNow;
}
mChildOfContent.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight()
{
mChildOfContent.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
return contentAreaOfWindowBounds.height();
}
}
--------------------------------------------------
Then class this class in your Activity or Fragment where you want a Layout
setContentView(R.layout.your_layout);
AlignLayoutDesign(this);
不幸的是,谷歌已经在Android上做了一个真正的狗牌Keyboards,并且顽固地拒绝纠正它。他们拒绝为键盘状态的改变或获得键盘大小的方法添加回调。此外,他们处理可见屏幕的大小调整和平移的方式不一致并且容易出错。在您的情况下,理想的情况是在键盘打开或关闭时触发事件,其中包含键盘的大小。尝试我创建的以下实用程序服务。它并不完美,但即使在调试模式和硬件键盘上也能正常工作,并且可以根据需要灵活调整。
public class KeyboardStatusService
{
public delegate void KeyboardStatusChangeEventHandler(KeyboardStatusChangeEventArgs e);
public event KeyboardStatusChangeEventHandler KeyboardStatusChangeEvent;
private int _openHeightDelta = -1;
private int _closedHeightDelta = 0;
private InputMethodManager __imm = null;
private InputMethodManager _imm
{
get
{
if (__imm == null || __imm.Handle == IntPtr.Zero)
__imm = BaseApplication.CurrentActivity?.GetSystemService(Context.InputMethodService) as InputMethodManager;
return __imm;
}
}
public KeyboardStatus Status { get; private set; } = KeyboardStatus.Closed; // Default to closed when the app starts
public bool Subscribed { get; private set; } = false;
// Threshold used to remove false positives
public int Threshold { get; set; } = 144;
public void Subscribe()
{
Subscribe(BaseApplication.CurrentActivity);
}
public void Subscribe(Activity activity)
{
if (!Subscribed)
{
var rootLayout = activity?.Window.DecorView; //.FindViewById(global::Android.Resource.Id.Content);
if (rootLayout != null)
{
// Subscribe to ViewTreeObserver.GlobalLayout
rootLayout.ViewTreeObserver.GlobalLayout += LayoutChangeDetected;
Subscribed = true; // so we only ever subscribe once
}
}
}
private async void LayoutChangeDetected(object sender, EventArgs e)
{
await Task.Run(() => { LayoutChangeDetected(); }).ConfigureAwait(false);
}
private void LayoutChangeDetected()
{
var open = _imm.IsAcceptingText;
if (Status == KeyboardStatus.Closed && open) // was closed. now open
{
var rootLayout = BaseApplication.CurrentActivity.Window.DecorView;
Rect r = new Rect();
rootLayout.GetWindowVisibleDisplayFrame(r);
Rect r1 = new Rect();
rootLayout.GetLocalVisibleRect(r1);
var heightDelta = r1.Bottom - r.Bottom;
// Double check (in case we have manually changed layouts in response to the keyboard opening and closing
if (heightDelta > _closedHeightDelta + Threshold) // may need to add padding here to account for other layout changes
{
if (_openHeightDelta == -1)
_openHeightDelta = heightDelta;
Status = KeyboardStatus.Open;
// Trigger the event
KeyboardStatusChangeEvent?.Invoke(new KeyboardStatusChangeEventArgs(Status, _openHeightDelta));
}
}
else if (Status == KeyboardStatus.Open)
{
if (!open) // was open. now closed - this handles when an action results in EditText losing focus and input ability
{
Status = KeyboardStatus.Closed;
// Trigger the event
KeyboardStatusChangeEvent?.Invoke(new KeyboardStatusChangeEventArgs(Status, _closedHeightDelta));
}
else
{
// some actions don't result in edit Text losing focus or input ability, such as keyboard dismiss button.
// This may be limited to when a hardware keyboard is attached, such as when debugging
var rootLayout = BaseApplication.CurrentActivity.Window.DecorView;
Rect r = new Rect();
rootLayout.GetWindowVisibleDisplayFrame(r);
Rect r1 = new Rect();
rootLayout.GetLocalVisibleRect(r1);
var heightDelta = r1.Bottom - r.Bottom;
if (heightDelta < _openHeightDelta - Threshold) // may need to add padding here to account for other layout changes
{
_closedHeightDelta = heightDelta;
Status = KeyboardStatus.Closed;
// Trigger the event
KeyboardStatusChangeEvent?.Invoke(new KeyboardStatusChangeEventArgs(Status, _closedHeightDelta));
}
}
}
}
public void Unsubscribe()
{
Unsubscribe(BaseApplication.CurrentActivity);
}
public void Unsubscribe(Activity activity)
{
var rootLayout = activity?.Window.DecorView; //.FindViewById(global::Android.Resource.Id.Content);
if (rootLayout != null)
{
rootLayout.ViewTreeObserver.GlobalLayout -= LayoutChangeDetected; // Don't need to check for subscribed as wont cause an issue
Subscribed = false;
}
}
public static void DismissKeyboard(Activity activity, View view)
{
if (view == null)
view = new View(activity);
InputMethodManager iMM = (InputMethodManager)activity.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(Context ctx, View view)
{
if (view == null)
view = new View(ctx);
InputMethodManager iMM = (InputMethodManager)ctx.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(Context ctx, Fragment fragment)
{
var view = fragment.View.RootView;
InputMethodManager iMM = (InputMethodManager)ctx.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(Context ctx, global::Android.Support.V4.App.Fragment fragment)
{
var view = fragment.View.RootView;
InputMethodManager iMM = (InputMethodManager)ctx.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(Fragment fragment)
{
var view = fragment.View.RootView;
InputMethodManager iMM = (InputMethodManager)fragment.Activity.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(global::Android.Support.V4.App.Fragment fragment)
{
var view = fragment.View.RootView;
InputMethodManager iMM = (InputMethodManager)fragment.Activity.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void DismissKeyboard(Activity activity)
{
var view = activity.FindViewById(global::Android.Resource.Id.Content).RootView;
InputMethodManager iMM = (InputMethodManager)activity.GetSystemService(Context.InputMethodService);
iMM.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
view.ClearFocus();
}
public static void ToggleKeyboard(Activity activity)
{
InputMethodManager iMM = (InputMethodManager)activity.GetSystemService(Context.InputMethodService);
iMM.ToggleSoftInput(ShowFlags.Implicit, HideSoftInputFlags.ImplicitOnly);
}
public static void ShowKeyboard(Activity activity, View view, bool forced = false)
{
if (view == null)
view = new View(activity);
InputMethodManager iMM = (InputMethodManager)activity.GetSystemService(Context.InputMethodService);
if (forced)
iMM.ShowSoftInput(view, ShowFlags.Forced);
else
iMM.ShowSoftInput(view, ShowFlags.Implicit);
}
public static void ShowKeyboard(Context ctx, View view, bool forced = false)
{
if (view == null)
view = new View(ctx);
InputMethodManager iMM = (InputMethodManager)ctx.GetSystemService(Context.InputMethodService);
if (forced)
iMM.ShowSoftInput(view, ShowFlags.Forced);
else
iMM.ShowSoftInput(view, ShowFlags.Implicit);
}
}
public enum KeyboardStatus
{
Closed,
Open,
Unknown
}
public class KeyboardStatusChangeEventArgs : EventArgs
{
public KeyboardStatus Status { get; private set; } = KeyboardStatus.Unknown;
public int VisibleHeightToDecorHeightDelta { get; private set; } = -1;
public KeyboardStatusChangeEventArgs(KeyboardStatus status, int visibleHeightToDecorHeightDelta)
{
Status = status;
VisibleHeightToDecorHeightDelta = visibleHeightToDecorHeightDelta;
}
}
然后在您的活动中订阅/取消订阅,如下所示:
private KeyboardStatusService KeyboardStatus { get; } = new KeyboardStatusService();
private int _keyboardHeight;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
KeyboardStatus.Subscribe(this);
KeyboardStatus.KeyboardStatusChangeEvent += OnKeyboardStatusChanged;
...........
}
protected override void OnDestroy()
{
base.OnDestroy();
KeyboardStatus.KeyboardStatusChangeEvent -= OnKeyboardStatusChanged;
KeyboardStatus.Unsubscribe(this);
........
}
private void OnKeyboardStatusChanged(KeyboardStatusChangeEventArgs e)
{
var keyboardStatus = e.Status;
if (keyboardStatus == KeyboardStatus.Open)
{
var heightDelta = e.VisibleHeightToDecorHeightDelta;
// need to adjust keyboard height calculation based upon the prescribed adjustment for the Activity set as WindowSoftInputMode
// the presence of a toolbar and.or status bar
_keyboardHeight = heightDelta - YourToolBarHeight - YourStatusBarHeight;
// ADJUST THE HEIGHT OF YOUR VIEW HERE
}
else
{
// ADJUST THE HEIGHT OF YOUR VIEW HERE
}
}
这是BaseApplication:
public partial class BaseApplication: Application, Application.IActivityLifecycleCallbacks
{
public int NumberActivitiesActive { get; protected set; }
public static ApplicationState ApplicationState { get; protected set; } = ApplicationState.NotRunning;
public static DateTime AppEnteredTime { get; protected set; } = DateTime.MinValue;
public static DateTime AppLeftTime { get; protected set; } = DateTime.MinValue;
public static double TimeInAppMs
{
get
{
if (AppLeftTime == DateTime.MinValue)
return DateTime.Now.Subtract(AppEnteredTime).TotalMilliseconds;
else
return AppLeftTime.Subtract(AppEnteredTime).TotalMilliseconds;
}
}
public static Activity CurrentActivity { get; private set; }
// Used to store activities to be excluded from counts, such as Activities used to handle notifications in response to push notifications
public static List<string> ExcludedActivities { get; } = new List<string>();
public static void RegisterExcludedActivity(string activityName)
{
if (!ExcludedActivities.Contains(activityName))
ExcludedActivities.Add(activityName);
}
public static void UnregisterExcludedActivity(string activityName)
{
ExcludedActivities.Remove(activityName);
}
public BaseApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
ApplicationState = ApplicationState.NotRunning;
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
ApplicationState = ApplicationState.NotRunning;
}
public virtual void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CurrentActivity = activity;
}
public virtual void OnActivityDestroyed(Activity activity) // Exclude this activity because it only relates to a notification created in response to a push notification
{
if (!ExcludedActivities.Contains(activity.LocalClassName) && NumberActivitiesActive <= 0)
ApplicationState = ApplicationState.NotRunning;
}
public virtual void OnActivityPaused(Activity activity)
{
}
public virtual void OnActivityResumed(Activity activity)
{
CurrentActivity = activity;
}
public virtual void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public virtual void OnActivityStarted(Activity activity)
{
CurrentActivity = activity;
if (!ExcludedActivities.Contains(activity.LocalClassName))
{
if (NumberActivitiesActive == 0)
{
AppEnteredTime = DateTime.Now;
ApplicationState = ApplicationState.Foreground;
}
NumberActivitiesActive++;
}
}
public virtual void OnActivityStopped(Activity activity)
{
if (!ExcludedActivities.Contains(activity.LocalClassName))
{
NumberActivitiesActive--;
if (NumberActivitiesActive == 0)
{
AppLeftTime = DateTime.Now;
if (activity.IsFinishing)
ApplicationState = ApplicationState.NotRunning;
else
ApplicationState = ApplicationState.Background;
}
}
}
}
public enum ApplicationState
{
Background,
Foreground,
NotRunning,
Unknown
}
要使用基本应用程序,您需要在项目中声明从Base Application继承的MainApplication,并为其提供[Application]注释,如下所示:
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public partial class MainApplication : BaseApplication
{
public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }
}