[android] ListView 내부의 Focusable EditText

나는 지금까지 약 6 시간을 보냈고, 장애물에 부딪혔다. 일반적인 전제는 ListView(어댑터에 의해 생성되었는지 또는 헤더보기로 추가되었는지 여부에 관계없이) EditText위젯 및 Button. 내가 원하는 것은 조그 볼 / 화살표를 사용하여 선택기를 평소와 같이 개별 항목으로 이동할 수있는 것뿐입니다.하지만 특정 행에 도달하면 (명시 적으로 행을 식별해야하는 경우에도) 포커스가있는 선택기를 사용하여 위치를 표시하는 대신 그 아이가 초점을 맞추기를 원합니다.

나는 많은 가능성을 시도했지만 지금까지 운이 없었습니다.

나열한 것:

<ListView
    android:id="@android:id/list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

헤더보기 :

EditText view = new EditText(this);
listView.addHeaderView(view, null, true);

어댑터에 다른 항목이 있다고 가정하면 화살표 키를 사용하여 예상대로 목록에서 선택 항목을 위 / 아래로 이동합니다. 그러나 머리글 행 EditText에 도달 하면 선택기와 함께 표시되며 조그 볼을 사용하여 집중할 방법이 없습니다 . 참고 :을 탭하면 해당 지점에 초점 EditText 맞춰 지지만 터치 스크린에 의존하므로 필수 사항은 아닙니다.

ListView이 점에서 분명히 두 가지 모드가 있습니다.
1. setItemsCanFocus(true): 선택기가 표시되지 않지만 EditText화살표를 사용하면 초점을 맞출 수 있습니다. 포커스 검색 알고리즘은 예측하기 어렵고 어떤 항목이 선택되었는지에 대한 시각적 피드백 (모든 행 : 포커스 가능한 자식 포함 여부)이 없으므로 둘 다 사용자에게 예기치 않은 경험을 제공 할 수 있습니다.
2. setItemsCanFocus(false): 선택기는 항상 비 터치 모드로 그려지며, EditText탭해도 초점을 맞출 수 없습니다.

설상가상으로, 호출 editTextView.requestFocus()은 true를 반환하지만 실제로는 EditText 포커스를 제공하지 않습니다.

내가 구상하고있는 것은 기본적으로 1과 2의 하이브리드입니다. 모든 항목에 초점을 맞출 수 있는지 여부를 목록 설정이 아닌 목록 의 단일 항목에 대해 초점을 설정 하여 선택기가 선택에서 원활하게 전환되도록합니다. 초점을 맞출 수없는 항목에 대한 전체 행과 초점을 맞출 수있는 하위 항목이 포함 된 항목에 대한 초점 트리를 순회합니다.

수취인이 있습니까?



답변

죄송합니다. 제 질문에 답했습니다. 가장 정확하거나 가장 우아한 솔루션이 아닐 수도 있지만 저에게 효과적이며 매우 견고한 사용자 경험을 제공합니다. 두 가지 동작이 왜 그렇게 다른지 확인하기 위해 ListView의 코드를 살펴본 결과 ListView.java에서이 문제를 발견했습니다.

    public void setItemsCanFocus(boolean itemsCanFocus) {
        mItemsCanFocus = itemsCanFocus;
        if (!itemsCanFocus) {
            setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        }
    }

따라서를 호출 할 때 setItemsCanFocus(false)자식이 포커스를받을 수 없도록 하위 포커스 가능성도 설정합니다. 이것은 mItemsCanFocusListView의 OnItemSelectedListener에서 토글 할 수없는 이유를 설명합니다 . ListView가 모든 자식에 대한 포커스를 차단했기 때문입니다.

내가 지금 가지고있는 것 :

<ListView
    android:id="@android:id/list"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:descendantFocusability="beforeDescendants"
    />

beforeDescendants선택기는 ListView 자체 (자식 아님)에 포커스가있을 때만 그려지기 때문에 사용 하므로 기본 동작은 ListView가 먼저 포커스를 받고 선택기를 그리는 것이어야합니다.

그런 다음 OnItemSelectedListener에서 선택기를 재정의하려는 헤더 뷰를 알고 있으므로 (주어진 위치에 포커스 가능한 뷰가 포함되어 있는지 동적으로 확인하려면 더 많은 작업이 필요함) 하위 포커스 가능성을 변경하고 EditText에 포커스를 설정할 수 있습니다. 그 헤더에서 벗어나면 다시 변경합니다.

public void onItemSelected(AdapterView<?> listView, View view, int position, long id)
{
    if (position == 1)
    {
        // listView.setItemsCanFocus(true);

        // Use afterDescendants, because I don't want the ListView to steal focus
        listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        myEditText.requestFocus();
    }
    else
    {
        if (!listView.isFocused())
        {
            // listView.setItemsCanFocus(false);

            // Use beforeDescendants so that the EditText doesn't re-take focus
            listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
            listView.requestFocus();
        }
    }
}

public void onNothingSelected(AdapterView<?> listView)
{
    // This happens when you start scrolling, so we need to prevent it from staying
    // in the afterDescendants mode if the EditText was focused 
    listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}

주석 처리 된 setItemsCanFocus호출에 유의하십시오 . 이러한 호출로 올바른 동작을 얻었지만 setItemsCanFocus(false)포커스가 EditText에서 ListView 외부의 다른 위젯으로 이동하고 ListView로 돌아가서 다음 선택된 항목에 선택기를 표시했으며 그 점프 포커스가 산만 해졌습니다. ItemsCanFocus 변경 사항을 제거하고 하위 포커스 기능을 전환하여 원하는 동작을 얻었습니다. 모든 항목은 정상적으로 선택기를 그리지 만 EditText가있는 행에 도달하면 대신 텍스트 필드에 초점을 맞췄습니다. 그런 다음 해당 EditText를 계속할 때 선택기를 다시 그리기 시작했습니다.


답변

이것은 나를 도왔다.
매니페스트에서 :

<activity android:name= ".yourActivity" android:windowSoftInputMode="adjustPan"/>


답변

내 임무는 ListView클릭하면 확장되는 것을 구현 하는 것이 었습니다 . 추가 공간은 EditText텍스트를 입력 할 수있는 위치를 보여줍니다 . 앱은 2.2 이상에서 작동해야합니다 (이 문서 작성시 최대 4.2.2).

이 게시물과 내가 찾을 수있는 다른 솔루션에서 수많은 솔루션을 시도했습니다. 2.2 ~ 4.2.2 장치에서 테스트했습니다. 2.2+ 모든 장치에서 만족스러운 솔루션은 없었으며 각 솔루션은 서로 다른 문제를 나타 냈습니다.

최종 솔루션을 공유하고 싶었습니다.

  1. listview를 다음으로 설정 android:descendantFocusability="afterDescendants"
  2. listview를 다음으로 설정 setItemsCanFocus(true);
  3. 당신의 활동을 android:windowSoftInputMode="adjustResize"
    많은 사람들이 제안 adjustPan하지만 adjustResize훨씬 더 나은 ux imho를 제공합니다. 당신의 경우에 이것을 테스트하십시오. 와adjustPan 당신이 얻을 것이다 아래 많은 ListItems는 예를 들어 가려. 문서에 따르면 ( “일반적으로 크기 조정보다 바람직하지 않음”). 또한 4.0.4에서 사용자가 소프트 키보드로 입력을 시작하면 화면이 맨 위로 이동합니다.
  4. 4.2.2에서는 adjustResizeEditText 포커스에 몇 가지 문제가 있습니다. 해결책은이 스레드에서 rjrjr 솔루션을 적용하는 것입니다. 무섭게 보이지만 그렇지 않습니다. 그리고 작동합니다. 먹어봐.

추가 5.EditText HoneyComb 이전 버전에 초점을 맞출 때 어댑터가 새로 고쳐 졌기 때문에 (보기 크기 조정으로 인해) 반전 된보기에서 문제가 발견
되었습니다. 2.2에서 ListView 항목보기 / 역순으로보기; 4.0.3에서 작동

일부 애니메이션을 수행하는 경우 adjustPan크기 조정이 실행되지 않고 어댑터가 뷰를 새로 고치지 않도록 벌집 이전 버전의 동작을로 변경할 수 있습니다. 다음과 같이 추가하면됩니다.

if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

이 모든 것이 2.2-4.2.2 장치에서 허용 가능한 UX를 제공합니다. 이 결론에 도달하는 데 최소한 몇 시간이 걸렸기 때문에 사람들이 시간을 절약 할 수 있기를 바랍니다.


답변

이것은 내 생명을 구했습니다 —>

  1. 이 줄을 설정

    ListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

  2. 그런 다음 활동 태그의 매니페스트에 this->를 입력하십시오.

    <activity android:windowSoftInputMode="adjustPan">

평소의 의도


답변

우리는보기 재활용을하지 않는 짧은 목록에서 이것을 시도하고 있습니다. 여태까지는 그런대로 잘됐다.

XML :

<RitalinLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
  <ListView
      android:id="@+id/cart_list"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scrollbarStyle="outsideOverlay"
      />
</RitalinLayout>

자바:

/**
 * It helps you keep focused.
 *
 * For use as a parent of {@link android.widget.ListView}s that need to use EditText
 * children for inline editing.
 */
public class RitalinLayout extends FrameLayout {
  View sticky;

  public RitalinLayout(Context context, AttributeSet attrs) {
    super(context, attrs);

    ViewTreeObserver vto = getViewTreeObserver();

    vto.addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
      @Override public void onGlobalFocusChanged(View oldFocus, View newFocus) {
        if (newFocus == null) return;

        View baby = getChildAt(0);

        if (newFocus != baby) {
          ViewParent parent = newFocus.getParent();
          while (parent != null && parent != parent.getParent()) {
            if (parent == baby) {
              sticky = newFocus;
              break;
            }
            parent = parent.getParent();
          }
        }
      }
    });

    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      @Override public void onGlobalLayout() {
        if (sticky != null) {
          sticky.requestFocus();
        }
      }
    });
  }
}


답변

이 게시물은 내 키워드와 정확히 일치했습니다. 검색 EditText 및 검색 버튼이있는 ListView 헤더가 있습니다.

초기 초점을 잃은 후 EditText에 초점을 맞추기 위해 내가 찾은 유일한 해킹은 다음과 같습니다.

    searchText.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            // LOTS OF HACKS TO MAKE THIS WORK.. UFF...
            searchButton.requestFocusFromTouch();
            searchText.requestFocus();
        }
    });

많은 시간을 잃었고 실제 수정이 아닙니다. 힘든 사람에게 도움이되기를 바랍니다.


답변

목록이 동적이고 포커스 가능한 위젯을 포함하는 경우 올바른 옵션은 ListView IMO 대신 RecyclerView 를 사용하는 것입니다.

adjustPan, 를 설정 FOCUS_AFTER_DESCENDANTS하거나 초점이 맞춰진 위치를 수동으로 기억하는 해결 방법은 실제로 해결 방법 일뿐입니다. 코너 케이스 (스크롤 + 소프트 키보드 문제, EditText에서 캐럿 위치 변경)가 있습니다. 그들은 ListView가 .NET 에서 한꺼번에 뷰를 생성 / 파괴한다는 사실을 변경하지 않습니다 notifyDataSetChanged.

RecyclerView를 사용하면 개별 삽입, 업데이트 및 삭제에 대해 알립니다. 포커스가있는 뷰가 다시 생성되지 않으므로 폼 컨트롤이 포커스를 잃는 문제가 없습니다. 추가 보너스로 RecyclerView는 목록 항목 삽입 및 제거에 애니메이션을 적용합니다.

다음은 시작하는 방법에 대한 공식 문서의 예입니다 RecyclerView. 개발자 가이드-RecyclerView로 목록 만들기