태그 보관물: android-widget

android-widget

Android 소프트 키보드가 표시 될 때 전체 화면 모드에서 레이아웃을 조정하는 방법 android:layout_height=”fill_parent” android:orientation=”vertical”>

소프트 키보드가 활성화되어있을 때 레이아웃을 조정하기 위해 많은 연구를했으며 성공적으로 구현했지만 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"매니페스트 파일의 활동 태그에서 이것을 사용할 때 문제가 발생 합니다.

이를 위해 나는 사용했다 android:windowSoftInputMode="adjustPan|adjustResize|stateHidden" 다른 옵션을 사용했지만 운이 없습니다.

그 후 나는 구현했다 FullScreen 프로그래밍 방식으로 하고 다양한 레이아웃을 시도 FullScreen했지만 모두 헛된 일을했습니다.

나는이 링크를 참조 하고이 문제와 관련된 많은 게시물을 보았습니다.

http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html

http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/

xml 코드는 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/masterContainerView"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#ffffff">

    <ScrollView android:id="@+id/parentScrollView"
        android:layout_width="fill_parent" android:layout_height="wrap_content">

        <LinearLayout android:layout_width="fill_parent"
            android:layout_height="fill_parent" android:orientation="vertical">

            <TextView android:id="@+id/setup_txt" android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:text="Setup - Step 1 of 3"
                android:textColor="@color/top_header_txt_color" android:textSize="20dp"
                android:padding="8dp" android:gravity="center_horizontal" />

            <TextView android:id="@+id/txt_header" android:layout_width="fill_parent"
                android:layout_height="40dp" android:text="AutoReply:"
                android:textColor="@color/top_header_txt_color" android:textSize="14dp"
                android:textStyle="bold" android:padding="10dp"
                android:layout_below="@+id/setup_txt" />

            <EditText android:id="@+id/edit_message"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:text="Some text here." android:textSize="16dp"
                android:textColor="@color/setting_editmsg_color" android:padding="10dp"
                android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header"
                android:gravity="top" android:scrollbars="vertical"
                android:maxLength="132" />

            <ImageView android:id="@+id/image_bottom"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:layout_below="@+id/edit_message" />

        </LinearLayout>
    </ScrollView>

    <RelativeLayout android:id="@+id/scoringContainerView"
        android:layout_width="fill_parent" android:layout_height="50px"
        android:orientation="vertical" android:layout_alignParentBottom="true"
        android:background="#535254">

        <Button android:id="@+id/btn_save" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_alignParentRight="true"
            android:layout_marginTop="7dp" android:layout_marginRight="15dp"
            android:layout_below="@+id/edit_message"
            android:text = "Save" />

        <Button android:id="@+id/btn_cancel" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_marginTop="7dp"
            android:layout_marginRight="10dp" android:layout_below="@+id/edit_message"
            android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" />

    </RelativeLayout>
</RelativeLayout>

여기에 이미지 설명을 입력하십시오

소프트 키보드가 그림에 나타날 때 하단 2 버튼이 위로 올라 가기를 원합니다.



답변

yghm의 해결 방법을 기반으로 한 클래스의 문제를 해결할 수있는 편리한 클래스를 작성했습니다 (물론 소스 코드에 새 클래스를 추가 한 후). 하나의 라이너는 다음과 같습니다.

     AndroidBug5497Workaround.assistActivity(this);

구현 클래스는 다음과 같습니다.


public class AndroidBug5497Workaround {

    // For more information, see https://issuetracker.google.com/issues/36911528
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static void assistActivity (Activity activity) {
        new AndroidBug5497Workaround(activity);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        });
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard/4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom - r.top);
    }
}

이것이 누군가를 돕기를 바랍니다.


답변

답변이 이미 선택되어 있고 버그로 알려진 문제이므로 “가능한 해결 방법”을 추가 할 것이라고 생각했습니다.

소프트 키보드가 표시되면 전체 화면 모드를 전환 할 수 있습니다. 이를 통해 “adjustPan”이 올바르게 작동합니다.

즉, 여전히 응용 프로그램 테마의 일부로 @android : style / Theme.Black.NoTitleBar.Fullscreen 을 사용 하고 활동 창 소프트 입력 모드의 일부로 stateVisible | adjustResize를 사용하지만 함께 작동하려면 전체 화면 모드로 전환해야합니다 키보드가 나타나기 전에.

다음 코드를 사용하십시오.

전체 화면 모드 끄기

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

전체 화면 모드 켜기

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

참고-영감은 다음과 같습니다. 전체 화면 모드에서 제목 숨기기


답변

나는 Joseph Johnson으로부터 해결책을 시도 했지만 다른 것과 마찬가지로 내용과 키보드 사이의 틈새에 부딪쳤다. 전체 화면 모드를 사용할 때 소프트 입력 모드가 항상 이동 하기 때문에 문제가 발생 합니다. 이 패닝은 소프트 입력에 의해 숨겨 질 입력 필드를 활성화 할 때 Joseph의 솔루션을 방해합니다.

소프트 입력이 나타나면 내용이 먼저 원래 높이를 기준으로 패닝 된 다음 Joseph의 솔루션이 요청한 레이아웃에 따라 크기가 조정됩니다. 크기 조정 및 후속 레이아웃은 패닝을 취소하지 않으므로 간격이 생깁니다. 전체 이벤트 순서는 다음과 같습니다.

  1. 글로벌 레이아웃 리스너
  2. 패닝
  3. 내용의 레이아웃 (= 내용의 실제 크기 조정)

패닝을 비활성화 할 수는 없지만 내용 높이를 변경하여 팬 오프셋을 0으로 설정할 수 있습니다. 패닝이 발생하기 전에 실행되기 때문에 리스너에서 수행 할 수 있습니다. 컨텐츠 높이를 사용 가능한 높이로 설정하면 깜박임이없는 부드러운 사용자 환경이 만들어집니다.

나는 또한 이것들을 변경했다. 이 중 하나라도 문제가 발생하면 알려주십시오.

  • 사용 가능한 높이의 전환 결정 getWindowVisibleDisplayFrame. 는 Rect불필요한 쓰레기의 약간을 방지하기 위해 캐시됩니다.
  • 리스너도 제거하십시오. 이 기능은 전체 화면 요구 사항이 다른 여러 조각에 활동을 재사용 할 때 유용합니다.
  • 키보드를 표시하거나 숨기지 말고 항상 내용 높이를 보이는 디스플레이 프레임 높이로 설정하십시오.

Nexus 5와 16에서 24 사이의 API 레벨을 실행하는 화면에서 작은 화면에서 큰 화면으로 테스트되었습니다.

코드는 Kotlin으로 포팅되었지만 변경 사항을 Java로 다시 포팅하는 것은 간단합니다. 도움이 필요하면 알려주십시오.

class AndroidBug5497Workaround constructor(activity: Activity) {
    private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
    private val rootView = contentContainer.getChildAt(0)
    private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
    private val viewTreeObserver = rootView.viewTreeObserver
    private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }

    private val contentAreaOfWindowBounds = Rect()
    private var usableHeightPrevious = 0

    // I call this in "onResume()" of my fragment
    fun addListener() {
        viewTreeObserver.addOnGlobalLayoutListener(listener)
    }

    // I call this in "onPause()" of my fragment
    fun removeListener() {
        viewTreeObserver.removeOnGlobalLayoutListener(listener)
    }

    private fun possiblyResizeChildOfContent() {
        contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
        val usableHeightNow = contentAreaOfWindowBounds.height()
        if (usableHeightNow != usableHeightPrevious) {
            rootViewLayout.height = usableHeightNow
            // Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge.
            rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom)
            rootView.requestLayout()

            usableHeightPrevious = usableHeightNow
        }
    }
}

답변

시스템 UI 접근 방식 ( https://developer.android.com/training/system-ui/immersive.html )을 사용하는 경우 간단하고 안정적인 솔루션을 찾았습니다 .

를 사용하는 경우에 작동합니다 ( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN예 : 사용중인 경우).CoordinatorLayout .

그것은 작동하지 않습니다 WindowManager.LayoutParams.FLAG_FULLSCREEN(당신은 또한에 테마로 설정할 수있는 하나 android:windowFullscreen),하지만 당신은 유사한 효과를 얻을 수 있습니다 SYSTEM_UI_FLAG_LAYOUT_STABLE( “같은 시각 효과있다” 워드 프로세서에 따라 )이 솔루션은 다시 작동합니다.

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

Marshmallow를 실행하는 장치에서 테스트했습니다.

핵심은 소프트 키보드가 시스템 창 (예 : 상태 표시 줄 및 탐색 표시 줄) 중 하나이므로 WindowInsets시스템 에서 발송 한 정보는 정확하고 신뢰할 수있는 정보입니다.

DrawerLayout상태 표시 줄 뒤에 그리는 것과 같은 유스 케이스의 경우 상단 삽입 만 무시하고 하단 키보드를 적용하는 하단 삽입을 적용하는 레이아웃을 만들 수 있습니다.

내 습관은 다음과 같습니다 FrameLayout.

/**
 * Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
 * except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
 * and should not be set on this layout.
 */
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {

    public FitsSystemWindowsExceptTopFrameLayout(Context context) {
        super(context);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
                    insets.getSystemWindowInsetBottom());
            return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
        } else {
            return super.onApplyWindowInsets(insets);
        }
    }
}

그리고 그것을 사용하려면 :

<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>

이것은 이론적으로 미친 수정없이 모든 장치에 대해 작동해야하며 임의의 1/3또는 1/4화면 크기를 참조 하려고하는 해킹보다 훨씬 좋습니다 .

(API 16 이상이 필요하지만 Lollipop +에서만 전체 화면을 사용하여 상태 표시 줄 뒤에 그리기 때문에이 경우 가장 좋은 솔루션입니다.)


답변

노트는 그 해주십시오 android:windowSoftInputMode="adjustResize"때 작동하지 않습니다 WindowManager.LayoutParams.FLAG_FULLSCREEN활동에 대해 설정됩니다. 두 가지 옵션이 있습니다.

  1. 활동에 대해 전체 화면 모드를 비활성화하십시오. 전체 화면 모드에서는 활동 크기가 조정되지 않습니다. xml (활동의 주제를 변경하여) 또는 Java 코드에서이를 수행 할 수 있습니다. onCreate () 메소드에 다음 행을 추가하십시오.

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`

또는

  1. 전체 화면 모드를 달성하려면 다른 방법을 사용하십시오. onCreate () 메소드에 다음 코드를 추가하십시오.

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    View decorView = getWindow().getDecorView();
    // Hide the status bar.
    int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(uiOptions);`

방법 -2는 Android 4.1 이상에서만 작동합니다.


답변

나는이 문제에 직면해야했고 HTC one, galaxy s1, s2, s3, note 및 HTC 센세이션을 확인하는 작업이있었습니다.

레이아웃의 루트 뷰에 글로벌 레이아웃 리스너를 배치

mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
            public void onGlobalLayout() {
                checkHeightDifference();
            }
    });

거기에서 나는 높이 차이를 확인했고 화면의 높이 차이가 화면 높이의 3 분의 1보다 크면 키보드가 열려 있다고 가정 할 수 있습니다. 이 답변 에서 가져 왔습니다 .

private void checkHeightDifference(){
    // get screen frame rectangle 
    Rect r = new Rect();
    mRootView.getWindowVisibleDisplayFrame(r);
    // get screen height
    int screenHeight = mRootView.getRootView().getHeight();
    // calculate the height difference
    int heightDifference = screenHeight - (r.bottom - r.top);

    // if height difference is different then the last height difference and
    // is bigger then a third of the screen we can assume the keyboard is open
    if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) {
        // keyboard visiblevisible
        // get root view layout params
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        // set the root view height to screen height minus the height difference
        lp.height = screenHeight - heightDifference;
        // call request layout so the changes will take affect
        .requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    } else if (heightDifference != mLastHeightDifferece) {
        // keyboard hidden
        PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden");
        // get root view layout params and reset all the changes we have made when the keyboard opened.
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        lp.height = screenHeight;
        // call request layout so the changes will take affect
        mRootView.requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    }
}

이것은 아마도 총알 증거가 아니며 어쩌면 일부 장치에서는 작동하지 않지만 저에게 효과적이며 도움이되기를 바랍니다.


답변

Joseph Johnson 솔루션을 구현했으며 제대로 작동했습니다.이 솔루션을 사용한 후 응용 프로그램의 서랍이 제대로 닫히지 않는 경우가 있습니다. 사용자가 편집 텍스트가있는 조각을 닫을 때 리스너 removeOnGlobalLayoutListener를 제거하는 기능을 추가했습니다.

    //when the application uses full screen theme and the keyboard is shown the content not scrollable! 
//with this util it will be scrollable once again
//http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
public class AndroidBug5497Workaround {


    private static AndroidBug5497Workaround mInstance = null;
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    private ViewTreeObserver.OnGlobalLayoutListener _globalListener;

    // For more information, see https://code.google.com/p/android/issues/detail?id=5497
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static AndroidBug5497Workaround getInstance (Activity activity) {
        if(mInstance==null)
        {
            synchronized (AndroidBug5497Workaround.class)
            {
                mInstance = new AndroidBug5497Workaround(activity);
            }
        }
        return mInstance;
    }

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();

        _globalListener = new ViewTreeObserver.OnGlobalLayoutListener()
        {

            @Override
            public void onGlobalLayout()
            {
                 possiblyResizeChildOfContent();
            }
        };
    }

    public void setListener()
    {
         mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener);
    }

    public void removeListener()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener);
        } else {
            mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener);
        }
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard/4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom - r.top);
    }
}

내 편집 텍스트가있는 클래스를 사용합니다.

@Override
public void onStart()
{
    super.onStart();
    AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}

@Override
public void onStop()
{
    super.onStop();
    AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}