2018-10-26 안드로이드 TV Recyclerview 긴 버튼 또는 연속 버튼, 초점 분실
최근 안드로이드 TV 프로젝트 개발에서는 타임라인 앨범을 보여주기 위해 Recyclerview를 사용해 리모컨을 길게 누르거나 연속으로 빠르게 아래로 누르면 초점을 잃어버린다.
원인 분석
RecyclerView 어댑터를 설정한 후 데이터를 채우면 모든 item의view를 만들지 않습니다. 보통 화면의 Item만 만들 수 있습니다. 키를 길게 누르거나 빠르게 눌렀을 때 Recyclerview는 초점을 가져올 view를 만들지 못해 초점을 잃어버립니다.
해결 방법
두 가지 사고방식이 있다. (1) 버튼 속도를 제어하는 것(개인적으로는 바람직하지 않다. 안드로이드 TV에서 초점 버튼 속도를 제어하는 것 참조) (2) Recyclerview에 LayoutManager를 설정하고 LayoutManager에서 초점을 RecyclerView의 LayoutManager에 제어하는 방법이 있다. onInterceptFocusSearch(View focused, int direction) 이 방법은 초점을 찾는 데 쓰인다.버튼을 길게 누르거나 연속으로 누르면 초점이 날아갈 때 RecyclerView의 LayoutManager를 다시 불러와서 이 방법을 다시 써야 합니다.
public class FocusFixedLinearLayoutManager extends LinearLayoutManager {
private static final String TAG = "FocusFixedLinearLayoutManager";
private Context mContext;
private Object mCaller;
public FocusFixedLinearLayoutManager(Context context) {
super(context);
}
public FocusFixedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
mContext = context;
}
public FocusFixedLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public View onInterceptFocusSearch(View focused, int direction) {
// , , View.FOCUS_LEFT View.FOCUS_RIGHT
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
// ,
// int currentPosition = getPosition(focused);
int currentPosition = getPosition(getFocusedChild());
int count = getItemCount();
int lastVisiblePosition = findLastVisibleItemPosition();
// 1 item( 0 ), 0 item , ,
// RecyclerView , Fragment " "
if (direction == View.FOCUS_UP && currentPosition == 1) {
Log.i(TAG, "onInterceptFocusSearch: fixed Focus to ------");
scrollToPosition(0);
((ImgPreviewFragment)mCaller).fixedFocusToTabPhoto();
return null;
}
switch (direction) {
case View.FOCUS_DOWN:
currentPosition++;
break;
case View.FOCUS_UP:
currentPosition--;
break;
}
Log.i(TAG, "onInterceptFocusSearch: current position=" + currentPosition);
Log.i(TAG, "onInterceptFocusSearch: item count=" + count);
Log.i(TAG, "onInterceptFocusSearch: lastVisiblePosition=" + lastVisiblePosition);
if (direction == View.FOCUS_DOWN && currentPosition > lastVisiblePosition) {
Log.i(TAG, "onInterceptFocusSearch: update...");
scrollToPosition(currentPosition);
}
}
return super.onInterceptFocusSearch(focused, direction);
}
public void setFragmentObject(Object object) {
mCaller = object;
}
}
코드에서 Fragment에 관한 코드는 관심을 두지 않아도 된다. 이것은 버튼이 위로 올라갈 때 Recyclerview 맨 위에 미끄러지지 않을 수도 있고 맨 위에 미끄러진 후에tab 제목으로 돌아가지 못할 수도 있는 문제를 해결하는 것이다. 왜냐하면 타임라인의 시간이 첫 번째 Item이고 초점(첫 줄의 그림에 초점이 맞춰져 있기 때문에)이 없기 때문에 맨 위에 미끄러지지 않을 수도 있다.(내 UI 레이아웃은 ViewPager는 4개의 Fragment을 포함하고 Fragment는 tab 제목을 포함하며 Fragment는 Recyclerview를 포함한다)이기 때문에 첫 줄의 그림에 초점을 맞출 때 키 방향을 판단하고 위로 올라가면 scrollToPosition을 사용하여 Recyclerview를 위로 미끄러뜨리고 초점을 tab 제목에 강제로 설정한다.
위와 같은 방법은 일부 장면에서 문제가 있다. 예를 들어 위아래 버튼을 반복해서 누르면 다음 Item이 전시되지 않는 상황이 발생할 수 있다. 초점이 이동한 후에 다음 초점이 부분적으로 전시되어야 초점이 사라지는 현상이 발생하지 않도록 고려한다. 핵 코드는 다음과 같다. onInterceptFocusSearch에 다음과 같은 코드를 추가한다.
View focusItem = getFocusedChild();
// , , , , view ,
// View
if (direction == View.FOCUS_UP && nextPosition > 0) {
Log.i(TAG, "onInterceptFocusSearch: up: scroll to: " + nextPosition);
if (null != focusItem) {
float offsetY = focusItem.getTop();
// top view , , Item
if (offsetY <= mItemHeight) {
int finalOffset = mItemHeight - (int)offsetY;
scrollToPositionWithOffset(nextPosition, finalOffset);
}
// top view , , Item
if (offsetY <= (mItemHeight + mItemHeight / 2) && offsetY > mItemHeight) {
int finalOffset = (mItemHeight + mItemHeight / 2) - (int)offsetY;
scrollToPositionWithOffset(nextPosition, finalOffset);
}
}
}
// , position Item , , ,
// Item
if (direction == View.FOCUS_DOWN && nextPosition < getItemCount() - 2) {
Log.i(TAG, "onInterceptFocusSearch: down: scroll to: " + nextPosition);
if (null != focusItem) {
// bottom view , , Item
float offsetY = focusItem.getBottom();
if (offsetY >= mItemHeight) {
int finalOffset = (int)offsetY - mItemHeight + mItemHeight / 2;
scrollToPositionWithOffset(nextPosition, finalOffset);
}
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.