MFC实现子控件focus焦点上下移动父控件ListView和Gridview也跟着向上下移动

发布于:2024-06-04 ⋅ 阅读:(65) ⋅ 点赞:(0)

项目中要实现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;
        }
    }

实现成功:子控件焦点滑到中间,gridview父控件也跟着下滑了!!!