ฉันต้องการจะเปลี่ยนเลย์เอาต์ตามว่าแป้นพิมพ์เสมือนจริงแสดงหรือไม่ ฉันค้นหา API และบล็อกต่างๆ แต่ดูเหมือนจะไม่พบสิ่งใดที่มีประโยชน์
เป็นไปได้ไหม?
ขอบคุณ!
ฉันต้องการจะเปลี่ยนเลย์เอาต์ตามว่าแป้นพิมพ์เสมือนจริงแสดงหรือไม่ ฉันค้นหา API และบล็อกต่างๆ แต่ดูเหมือนจะไม่พบสิ่งใดที่มีประโยชน์
เป็นไปได้ไหม?
ขอบคุณ!
คำตอบ:
วิธีนี้จะไม่ทำงานกับคีย์บอร์ดที่อ่อนนุ่มและ
onConfigurationChanged
จะไม่ถูกเรียกสำหรับคีย์บอร์ดนุ่ม (เสมือน)
คุณต้องจัดการกับการเปลี่ยนแปลงการกำหนดค่าด้วยตัวเอง
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
ตัวอย่าง:
// from the link above
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a hardware keyboard is available
if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
} else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
}
จากนั้นเพียงเปลี่ยนการมองเห็นของบางมุมมองอัพเดตฟิลด์และเปลี่ยนไฟล์เลย์เอาต์ของคุณ
newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
~ Chris
นี่อาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่สิ่งนี้ใช้ได้กับฉันทุกครั้ง ... ฉันเรียกฟังก์ชั่นนี้ซึ่งฉันจำเป็นต้องฟัง softKeyboard
boolean isOpened = false;
public void setListenerToRootView() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
Toast.makeText(getApplicationContext(), "Gotcha!!! softKeyboardup", 0).show();
if (isOpened == false) {
//Do two things, make the view top visible and the editText smaller
}
isOpened = true;
} else if (isOpened == true) {
Toast.makeText(getApplicationContext(), "softkeyborad Down!!!", 0).show();
isOpened = false;
}
}
});
}
หมายเหตุ: วิธีการนี้จะทำให้เกิดปัญหาหากผู้ใช้ใช้แป้นพิมพ์ลอย
android:windowSoftInputMode="adjustPan"
หรือadjustResize
หน้าต่างเต็มหน้าจอเนื่องจากไม่เคยปรับขนาดเค้าโครง
หากคุณต้องการจัดการแสดง / ซ่อนหน้าต่างแป้นพิมพ์ IMM (เสมือน) จากกิจกรรมของคุณคุณจะต้อง subclass เลย์เอาต์และแทนที่เมธอด onMesure ของคุณ (เพื่อให้คุณสามารถกำหนดความกว้างที่วัดได้และความสูงที่วัดได้ของโครงร่างของคุณ) หลังจากนั้นกำหนดเลย์เอาต์คลาสย่อยเป็นมุมมองหลักสำหรับกิจกรรมของคุณโดย setContentView () ตอนนี้คุณจะสามารถจัดการแสดง / ซ่อนเหตุการณ์หน้าต่างของ IMM ถ้ามันฟังดูซับซ้อนก็ไม่เป็นเช่นนั้น นี่คือรหัส:
main.xml
<?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="horizontal" >
<EditText
android:id="@+id/SearchText"
android:text=""
android:inputType="text"
android:layout_width="fill_parent"
android:layout_height="34dip"
android:singleLine="True"
/>
<Button
android:id="@+id/Search"
android:layout_width="60dip"
android:layout_height="34dip"
android:gravity = "center"
/>
</LinearLayout>
ตอนนี้ในกิจกรรมของคุณประกาศคลาสย่อยสำหรับโครงร่างของคุณ (main.xml)
public class MainSearchLayout extends LinearLayout {
public MainSearchLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("Search Layout", "Handling Keyboard Window shown");
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
if (actualHeight > proposedheight){
// Keyboard is shown
} else {
// Keyboard is hidden
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
คุณสามารถดูได้จากรหัสที่เราขยายเค้าโครงสำหรับกิจกรรมของเราในตัวสร้างคลาสย่อย
inflater.inflate(R.layout.main, this);
และตอนนี้เพียงแค่ตั้งค่ามุมมองเนื้อหาของโครงร่างย่อยสำหรับกิจกรรมของเรา
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainSearchLayout searchLayout = new MainSearchLayout(this, null);
setContentView(searchLayout);
}
// rest of the Activity code and subclassed layout...
}
android:windowSoftInputMode="adjustPan"
หรือadjustResize
หน้าต่างเต็มหน้าจอเนื่องจากไม่ได้ปรับขนาดเค้าโครง
ฉันทำอย่างนี้:
เพิ่มOnKeyboardVisibilityListener
ส่วนต่อประสาน
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
HomeActivity.java :
public class HomeActivity extends Activity implements OnKeyboardVisibilityListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
// Other stuff...
setKeyboardVisibilityListener(this);
}
private void setKeyboardVisibilityListener(final OnKeyboardVisibilityListener onKeyboardVisibilityListener) {
final View parentView = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);
parentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private boolean alreadyOpen;
private final int defaultKeyboardHeightDP = 100;
private final int EstimatedKeyboardDP = defaultKeyboardHeightDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect rect = new Rect();
@Override
public void onGlobalLayout() {
int estimatedKeyboardHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, parentView.getResources().getDisplayMetrics());
parentView.getWindowVisibleDisplayFrame(rect);
int heightDiff = parentView.getRootView().getHeight() - (rect.bottom - rect.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == alreadyOpen) {
Log.i("Keyboard state", "Ignoring global layout change...");
return;
}
alreadyOpen = isShown;
onKeyboardVisibilityListener.onVisibilityChanged(isShown);
}
});
}
@Override
public void onVisibilityChanged(boolean visible) {
Toast.makeText(HomeActivity.this, visible ? "Keyboard is active" : "Keyboard is Inactive", Toast.LENGTH_SHORT).show();
}
}
หวังว่านี่จะช่วยคุณได้
จาก Code จาก Nebojsa Tomcic ฉันได้พัฒนา RelativeLayout-Subclass ดังต่อไปนี้
import java.util.ArrayList;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class KeyboardDetectorRelativeLayout extends RelativeLayout {
public interface IKeyboardChanged {
void onKeyboardShown();
void onKeyboardHidden();
}
private ArrayList<IKeyboardChanged> keyboardListener = new ArrayList<IKeyboardChanged>();
public KeyboardDetectorRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public KeyboardDetectorRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public KeyboardDetectorRelativeLayout(Context context) {
super(context);
}
public void addKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.add(listener);
}
public void removeKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.remove(listener);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
if (actualHeight > proposedheight) {
notifyKeyboardShown();
} else if (actualHeight < proposedheight) {
notifyKeyboardHidden();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void notifyKeyboardHidden() {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardHidden();
}
}
private void notifyKeyboardShown() {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardShown();
}
}
}
ใช้งานได้ดี ... ทำเครื่องหมายว่าโซลูชันนี้จะใช้งานได้เมื่อตั้งค่าโหมดการป้อนข้อมูลอ่อนของกิจกรรมของคุณเป็น "WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE"
android:windowSoftInputMode="adjustPan"
หรือadjustResize
หน้าต่างเต็มหน้าจอเนื่องจากไม่เคยปรับขนาดเค้าโครง
เช่นเดียวกับคำตอบของ @ amalBit ลงทะเบียนผู้ฟังในเลย์เอาต์ทั่วโลกและคำนวณความแตกต่างของด้านล่างที่มองเห็นได้ของ dectorView และด้านล่างที่เสนอถ้าความแตกต่างใหญ่กว่าค่าบางค่า (เดาความสูงของ IME) เราคิดว่า
final EditText edit = (EditText) findViewById(R.id.edittext);
edit.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (keyboardShown(edit.getRootView())) {
Log.d("keyboard", "keyboard UP");
} else {
Log.d("keyboard", "keyboard Down");
}
}
});
private boolean keyboardShown(View rootView) {
final int softKeyboardHeight = 100;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
int heightDiff = rootView.getBottom() - r.bottom;
return heightDiff > softKeyboardHeight * dm.density;
}
เกณฑ์ความสูง 100 คือความสูงขั้นต่ำที่คาดเดาได้ของ IME
ใช้งานได้ทั้ง adjustPan และ adjustResize
คำตอบของ Nebojsa นั้นใช้ได้กับฉันเกือบหมดแล้ว เมื่อฉันคลิกภายใน EditText แบบหลายบรรทัดจะรู้ว่าคีย์บอร์ดปรากฏขึ้น แต่เมื่อฉันเริ่มพิมพ์ภายใน EditText ค่าความสูงจริงและความสูงที่เสนอยังคงเหมือนเดิมดังนั้นจึงไม่ทราบว่าแป้นพิมพ์เหล่านั้นยังคงปรากฏอยู่ ฉันปรับเปลี่ยนเล็กน้อยเพื่อจัดเก็บความสูงสูงสุดและใช้งานได้ดี นี่คือคลาสย่อยที่แก้ไข:
public class CheckinLayout extends RelativeLayout {
private int largestHeight;
public CheckinLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.checkin, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
largestHeight = Math.max(largestHeight, getHeight());
if (largestHeight > proposedheight)
// Keyboard is shown
else
// Keyboard is hidden
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
ไม่แน่ใจว่ามีใครโพสต์สิ่งนี้หรือไม่ พบโซลูชันนี้ใช้งานง่าย! . ระดับ softkeyboard อยู่บน gist.github.com แต่ในขณะที่แป้นพิมพ์ป๊อปอัป / ซ่อนการโทรกลับเหตุการณ์เราต้องใช้ตัวจัดการเพื่อทำสิ่งต่าง ๆ บน UI อย่างถูกต้อง:
/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use your root layout
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
@Override
public void onSoftKeyboardHide()
{
// Code here
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
...
}
});
}
@Override
public void onSoftKeyboardShow()
{
// Code here
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
...
}
});
}
});
ฉันแก้ปัญหานี้โดยการเอาชนะ onKeyPreIme (int keyCode, KeyEvent event) ใน EditText ที่กำหนดเองของฉัน
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
//keyboard will be hidden
}
}
ฉันมีแฮ็คที่จะทำเช่นนี้ แม้ว่าจะมีไม่ได้ดูเหมือนจะเป็นวิธีการในการตรวจสอบเมื่อแป้นพิมพ์อ่อนได้แสดงหรือซ่อนคุณสามารถในความเป็นจริงการตรวจสอบเมื่อมันเป็นเรื่องเกี่ยวกับที่จะแสดงหรือซ่อนโดยการตั้งค่าOnFocusChangeListener
ในEditText
ที่คุณกำลังฟังไป
EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
{
@Override
public void onFocusChange(View view, boolean hasFocus)
{
//hasFocus tells us whether soft keyboard is about to show
}
});
หมายเหตุ:สิ่งหนึ่งที่ต้องระวังเกี่ยวกับการแฮ็คนี้คือการโทรกลับนี้ถูกไล่ออกทันทีเมื่อEditText
ได้รับหรือเสียโฟกัส สิ่งนี้จะดำเนินการทันทีก่อนที่คีย์บอร์ดจะแสดงหรือซ่อน วิธีที่ดีที่สุดที่ฉันพบว่าทำอะไรบางอย่างหลังจากการแสดงหรือซ่อนคีย์บอร์ดคือการใช้Handler
และหน่วงเวลาบางอย่าง ~ 400ms เช่น:
EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
{
@Override
public void onFocusChange(View view, boolean hasFocus)
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
//do work here
}
}, 400);
}
});
OnFocusChangeListener
เพียงบอกว่าEditText
มีโฟกัสหลังจากเปลี่ยนสถานะหรือไม่ แต่IME
อาจถูกซ่อนไว้เมื่อEditText
มีโฟกัสวิธีการตรวจสอบกรณีนี้หรือไม่
ฉันเชื่อว่าคุณกำลังพยายามแสดงมุมมองที่ถูกบล็อกโดยคีย์บอร์ดนุ่ม ลองhttp://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.htmlนี้
ฉันได้แก้ปัญหาในการเข้ารหัส textview กลับบรรทัดเดียว
package com.helpingdoc;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
public class MainSearchLayout extends LinearLayout {
int hieght = 0;
public MainSearchLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("Search Layout", "Handling Keyboard Window shown");
if(getHeight()>hieght){
hieght = getHeight();
}
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
System.out.println("....hieght = "+ hieght);
System.out.println("....actualhieght = "+ actualHeight);
System.out.println("....proposedheight = "+ proposedheight);
if (actualHeight > proposedheight){
// Keyboard is shown
} else if(actualHeight<proposedheight){
// Keyboard is hidden
}
if(proposedheight == hieght){
// Keyboard is hidden
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
คุณสามารถตรวจสอบช่องว่างด้านล่างของลูกแรกของ DecorView มันจะถูกตั้งค่าเป็นค่าที่ไม่เป็นศูนย์เมื่อมีการแสดงแป้นพิมพ์
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
View view = getRootView();
if (view != null && (view = ((ViewGroup) view).getChildAt(0)) != null) {
setKeyboardVisible(view.getPaddingBottom() > 0);
}
super.onLayout(changed, left, top, right, bottom);
}
ซ่อน | แสดงกิจกรรมสำหรับแป้นพิมพ์สามารถฟังผ่านแฮ็คธรรมดาใน OnGlobalLayoutListener:
final View activityRootView = findViewById(R.id.top_root);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) {
// keyboard is up
} else {
// keyboard is down
}
}
});
ที่นี่ activityRootView คือมุมมองรูทของกิจกรรม
ใช้viewTreeObserverเพื่อรับเหตุการณ์คีย์บอร์ดอย่างง่ายดาย
layout_parent.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
layout_parent.getWindowVisibleDisplayFrame(r)
if (layout_parent.rootView.height - (r.bottom - r.top) > 100) { // if more than 100 pixels, its probably a keyboard...
Log.e("TAG:", "keyboard open")
} else {
Log.e("TAG:", "keyboard close")
}
}
** layout_parentเป็นมุมมองของคุณเช่นedit_text.parent
คำตอบของ Nebojsa Tomcic ไม่มีประโยชน์สำหรับฉัน ฉันมีRelativeLayout
กับTextView
และAutoCompleteTextView
ข้างในมัน ฉันต้องเลื่อนTextView
ไปด้านล่างเมื่อมีการแสดงแป้นพิมพ์และเมื่อมันถูกซ่อนอยู่ เพื่อให้บรรลุนี้ฉันเอาชนะonLayout
วิธีการและใช้งานได้ดีสำหรับฉัน
public class ExtendedLayout extends RelativeLayout
{
public ExtendedLayout(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
if (changed)
{
int scrollEnd = (textView.getLineCount() - textView.getHeight() /
textView.getLineHeight()) * textView.getLineHeight();
textView.scrollTo(0, scrollEnd);
}
}
}