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父控件也跟着下滑了!!!

相关推荐
张先shen19 分钟前
Elasticsearch RESTful API入门:全文搜索实战(Java版)
java·大数据·elasticsearch·搜索引擎·全文检索·restful
天河归来1 小时前
springboot框架redis开启管道批量写入数据
java·spring boot·redis
没有了遇见1 小时前
Android 通过 SO 库安全存储敏感数据,解决接口劫持问题
android
hsx6661 小时前
使用一个 RecyclerView 构建复杂多类型布局
android
hsx6661 小时前
利用 onMeasure、onLayout、onDraw 创建自定义 View
android
守城小轩1 小时前
Chromium 136 编译指南 - Android 篇:开发工具安装(三)
android·数据库·redis
张先shen1 小时前
Elasticsearch RESTful API入门:全文搜索实战
java·大数据·elasticsearch·搜索引擎·全文检索·restful
codervibe1 小时前
如何用 Spring Security 构建无状态权限控制系统(含角色菜单控制)
java·后端
codervibe1 小时前
项目中如何用策略模式实现多角色登录解耦?(附实战代码)
java·后端
TCChzp1 小时前
synchronized全链路解析:从字节码到JVM内核的锁实现与升级策略
java·jvm