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

项目中要实现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父控件也跟着下滑了!!!

相关推荐
救救孩子把6 分钟前
深入理解 Java 对象的内存布局
java
落落落sss8 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节14 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭20 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
我行我素,向往自由27 分钟前
速成java记录(上)
java·速成
代码敲上天.29 分钟前
数据库语句优化
android·数据库·adb
一直学习永不止步33 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
邵泽明33 分钟前
面试知识储备-多线程
java·面试·职场和发展
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript