项目中要实现mfc功能,然后子控件焦点下移,LIstView和Gridview父控件不会下移,所以就有这个文章。废话不多说直接上代码。
MFCGridView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.widget.GridView;
import com.baidu.navisdk.ui.util.MFCUtil;
public class MFCGridView extends GridView {
protected int lastPosition = -1;
protected boolean mHasRegister = false;
private final ViewTreeObserver.OnGlobalFocusChangeListener mFocusChangeListener =
new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (!isInTouchMode()) {
refreshListViewScroll(oldFocus, newFocus);
}
}
};
protected void refreshListViewScroll(View oldFocus, View newFocus) {
if (getVisibility() != VISIBLE) {
return;
}
if (newFocus == null) {
return;
}
ViewParent convertView = getConvertView(newFocus);
if (convertView == null) {
return;
}
if (!(convertView instanceof View)) {
return;
}
Object tagView = ((View) convertView).getTag();
if (!(tagView instanceof IMFCHolder)) {
if (lastPosition
!= getAdapter().getCount() - 1) {
smoothScrollToPositionFromTop(0, 0);
lastPosition = -1;
}
return;
}
int focusedPosition = -1;
View focusedChild = getFocusedChild();
if (focusedChild != null) {
focusedPosition = getPositionForView(focusedChild);
}
if (focusedPosition != lastPosition) {
smoothScrollToPositionFromTop(focusedPosition, 50);
lastPosition = focusedPosition;
}
}
protected ViewParent getConvertView(View newFocus) {
ViewParent lastView = null;
ViewParent parent = newFocus.getParent();
if (parent == this){
return (ViewParent) newFocus;
}
while (parent != null) {
if (parent == this) {
return lastView;
}
lastView = parent;
parent = parent.getParent();
}
return null;
}
public MFCGridView(Context context) {
super(context);
setFocusableInTouchMode(false);
}
public MFCGridView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusableInTouchMode(false);
}
public MFCGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setFocusableInTouchMode(false);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (MFCUtil.isMFCEnable()) {
if (!mHasRegister) {
getViewTreeObserver().addOnGlobalFocusChangeListener(mFocusChangeListener);
mHasRegister = true;
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (MFCUtil.isMFCEnable()) {
getViewTreeObserver().removeOnGlobalFocusChangeListener(mFocusChangeListener);
mHasRegister = false;
}
clearDisappearingChildren();
}
}
MFCGridView使用方法:xml中直接引用即可,无需其他操作
---------------------------------------------------------分割线---------------------------------------------------------
依赖类IMFCHolder.java
public interface IMFCHolder {
int getPosition();
}
MFCListView.java
import com.baidu.navisdk.ui.util.MFCUtil;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.widget.ListView;
public class MFCListView extends ListView {
protected boolean mHasRegister = false;
protected int lastPosition = -1;
private final ViewTreeObserver.OnGlobalFocusChangeListener mFocusChangeListener =
new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (!isInTouchMode()) {
refreshListViewScroll(oldFocus, newFocus);
}
}
};
protected void refreshListViewScroll(View oldFocus, View newFocus) {
if (getVisibility() != VISIBLE) {
return;
}
if (newFocus == null) {
return;
}
ViewParent convertView = getConvertView(newFocus);
if (convertView == null) {
return;
}
if (!(convertView instanceof View)) {
return;
}
Object tagView = ((View) convertView).getTag();
if (!(tagView instanceof IMFCHolder)) {
if (lastPosition
!= getAdapter().getCount() - getHeaderViewsCount() - getFooterViewsCount()
- 1) {
smoothScrollToPositionFromTop(0, 0);
lastPosition = -1;
}
return;
}
IMFCHolder imfcHolder = (IMFCHolder) tagView;
int position = imfcHolder.getPosition();
if (position != lastPosition) {
smoothScrollToPositionFromTop(position + getHeaderViewsCount(), 50);
lastPosition = position;
}
}
protected ViewParent getConvertView(View newFocus) {
ViewParent lastView = null;
ViewParent parent = newFocus.getParent();
if (parent == this){
return (ViewParent) newFocus;
}
while (parent != null) {
if (parent == this) {
return lastView;
}
lastView = parent;
parent = parent.getParent();
}
return null;
}
public MFCListView(Context context) {
super(context);
setFocusableInTouchMode(false);
}
public MFCListView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusableInTouchMode(false);
}
public MFCListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setFocusableInTouchMode(false);
}
public MFCListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setFocusableInTouchMode(false);
}
@Override
public View getFocusedChild() {
return null;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (MFCUtil.isMFCEnable()) {
if (!mHasRegister) {
getViewTreeObserver().addOnGlobalFocusChangeListener(mFocusChangeListener);
mHasRegister = true;
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (MFCUtil.isMFCEnable()) {
getViewTreeObserver().removeOnGlobalFocusChangeListener(mFocusChangeListener);
mHasRegister = false;
}
clearDisappearingChildren();
}
}
依赖类MFCUtil.java
package com.baidu.navisdk.ui.util;
import android.app.Activity;
import com.baidu.naviauto.appcommon.AppLog;
import java.util.ArrayList;
import java.util.List;
public class MFCUtil {
private static final String TAG = "MFCUtil";
public static final List<String> REQUEST_CHECK_LIST_STRING = new ArrayList<>();
public static boolean isMFCEnable() {
return true;
}
/**
* 返回false 不消费 调用者可以request
* 返回true 消费 调用者不可以request
* @param activity
* @param classname
* @return
*/
public static boolean requestCheck(Activity activity, String classname) {
if (activity == null) {
return true;
}
if (!isMFCEnable()) {
return true;
}
if (activity.getWindow().getDecorView().isInTouchMode()){
return true;
}
checkRequestCheckList(activity);
if (REQUEST_CHECK_LIST_STRING == null) {
AppLog.e(TAG, "checkRequestCheckList == " + classname);
return false;
}
for (int i = 0; i < REQUEST_CHECK_LIST_STRING.size(); i++) {
if (REQUEST_CHECK_LIST_STRING.get(i).equals(classname)) {
AppLog.e(TAG, "false == " + classname);
return false;
}
}
AppLog.e(TAG, "false finish == " + classname);
return false;
}
public static void checkRequestCheckList(Activity activity) {
if (REQUEST_CHECK_LIST_STRING != null && REQUEST_CHECK_LIST_STRING.size() == 0) {
REQUEST_CHECK_LIST_STRING.add("PowerNotification");
REQUEST_CHECK_LIST_STRING.add("RestrictionTipsView");
REQUEST_CHECK_LIST_STRING.add("RecommendTripTipsView");
REQUEST_CHECK_LIST_STRING.add("PushPoiNaviNotificationView");
REQUEST_CHECK_LIST_STRING.add("PushPoiNaviNotificationDialog");
REQUEST_CHECK_LIST_STRING.add("NaviAutoActivity");
}
}
public static void onDestory(){
if (REQUEST_CHECK_LIST_STRING != null){
REQUEST_CHECK_LIST_STRING.clear();
}
}
}
MFCListView实际使用例子:
1.xml代码中使用MFCListView类代替
2.adapter中,核心代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_column, null);
viewHolder = new ViewHolder();
viewHolder.textView = convertView.findViewById(R.id.text);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.position = position;
viewHolder.textView.setText(mProvinShotNameArr[position]);
return convertView;
}
public static class ViewHolder implements IMFCHolder {
TextView textView;
int position;
@Override
public int getPosition() {
return position;
}
}