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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/678371.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TiKV学习5:TiDB SQL执行流程

目录 1. DML语句读流程概要 2. DML语句写流程概要 3. DDL 流程概要 4. SQL的Parse和Compile 5. 读取的执行 6. 写入的执行 7. DDL的执行 8. 小结 1. DML语句读流程概要 TiDB Server接收sql并处理&#xff0c;TiKV负责持久化数据&#xff0c;PD提供TSO和Region的数据字典…

error /var/lib/jenkins/workspace/*/node_modules/node-sass: Command failed.

原因&#xff1a;node-sass版本不一致 版本图&#xff1a; 解决方案&#xff1a; 进入到jenkins项目目录下&#xff0c;修改package.json文件 将7.0.1改成6.0.1版本

《对马岛之魂:导演剪辑版》新鲜出炉,AOC电竞显示器与你并肩作战!

超越PS版本的画面表现&#xff0c;AOC U27G3XM助你轻松拉满游戏体验&#xff01; 近日&#xff0c;《对马岛之魂&#xff1a;导演剪辑版》正式登陆PC平台。这款备受期待的作品不仅在战斗机制和故事内容上进行了创新&#xff0c;还引入了更高级的图形选项和更丰富的自定义设置。…

性能测试(二)—— linux服务器监控性能测试

测试目的&#xff1a;发现服务器的性能瓶颈。配置的不同能够承载的最大任务数不同&#xff0c;能够承载的压力也不同 服务器性能测试范围 1.1 测试范围 CPU 内存 硬盘 网络 版本&#xff08;软件、应用版本&#xff09; 1.2 测试与生产配置不相同 多次性能压测预估 …

力扣----轮转数组

题目链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 思路一 我们可以在进行每次轮转的时候&#xff0c;先将数组的最后一个数据的值存储起来&#xff0c;接着将数组中前n-1个数据依次向后移&#xff0c;最后将存储起来的值赋给数组中的第一个数据。 …

运动模糊技术在AI绘画中的创新应用

引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;AI绘画已经成为艺术创作领域的一颗新星。它不仅改变了艺术家的创作方式&#xff0c;还为普通用户提供了前所未有的艺术体验。在众多AI绘画技术中&#xff0c;运动模糊技术以其独特的视觉效果和广泛的应用前景受到了广泛…

【排序】插入排序,希尔排序

前面我们讲述了冒泡排序和选择排序&#xff0c;我们本章讲的排序方法是插入排序&#xff0c;插入排序是希尔排序实现的基础函数&#xff0c;大家一定要好好理解插入排序的逻辑&#xff0c;这样才能在后面学习希尔排序的时候&#xff0c;更容易的去理解&#xff0c;我们直接开始…

3D分割新范式!浙大开源Reasoning3D:通过大视觉语言模型搞定3D部件分割

文章链接&#xff1a;https://arxiv.org/pdf/2405.19326 项目链接&#xff1a;http://tianrun-chen.github.io/Reason3D/ 今天和大家分享的是一项新任务&#xff1a;Zero-Shot 3D 推理分割&#xff0c;用于对象的部件搜索和定位。这是一种超越了以往类别特定的3D语义分割、3D…

韩语“对不起”怎么说?柯桥留学韩语培训

一、引言 在学习韩语的过程中&#xff0c;掌握如何表达歉意是非常重要的一部分。无论是日常交流还是正式场合&#xff0c;礼貌地说“对不起”能展现出你的修养和对他人的尊重。本文将详细介绍韩语中表示“对不起”的几种常用表达方式及其使用情境。 二、主体内容 1、详细解释 标…

冯喜运:6.4汇市观潮:今日黄金原油行情走势及操作策略

【黄金消息面分析】&#xff1a;在全球经济的波动中&#xff0c;美元和黄金市场的表现一直是投资者关注的焦点。最近&#xff0c;市场情绪和经济数据的波动对这两个市场产生了显著的影响。周二欧市早盘&#xff0c;现货黄金价格出现短线回调&#xff0c;金价跌破2340美元/盎司&…

【MyBatisPlus】MyBatisPlus条件查询

【MyBatisPlus】MyBatisPlus条件查询 文章目录 【MyBatisPlus】MyBatisPlus条件查询1、查询条件方式2、组合条件3、NULL值处理4、查询投影-设置【查询字段、分组】5、查询条件6、字段映射与表名映射问题导入 1、查询条件方式 MyBatisPlus将书写复杂的SQL查询条件进行了封装&…

基于ESP32-S3芯片的通用型无线模组方案,启明云端乐鑫一级代理商

随着物联网技术的飞速发展&#xff0c;智能设备正以前所未有的速度进入到我们的日常生活中&#xff0c;AIoT&#xff08;人工智能物联网&#xff09;已成为智能家居、智能设备、智能安防等领域的核心技术。 作为乐鑫一级代理商&#xff0c;基于ESP32-S3芯片&#xff0c;启明云…

武汉凯迪正大—开关柜综合试验台 通电试验车 开关柜通电测试台

产品概述 ​武汉凯迪正大KDGK-II 成套综合测试台用于高低压开关柜生产厂家对所生产的高低压开关柜进行出厂前的各项通电试验。它能提供各种交、直流电源&#xff0c;便于对开关柜的检测&#xff0c;提高工作效率。 技术参数 输入电源&#xff1a;三相四线AC380V 输出电压及电…

【JAVA架构】开发在线开具电子发票系统

【JAVA架构VUE】开发在线开具电子发票系统 对接税务厂家接口 实现销售发票开具 进项发票在线拉取 红冲发票在线开具 详细内容可以关注本人专栏等 销售发票开具 开具发票 进项发票在线拉取 红冲发票在线开具

YoloV9改进策略:Block篇|基于FasterNet的Block改进|性能和精度得到大幅度提高(独家原创)

本文使用FasterNet的Block改进YoloV9,对FasterNet的Block做了适当的修改,使其能够适配YoloV9,可以替换YoloV9的Bottleneck模块。 论文翻译:《CVPR2023年最新的网络,基于部分卷积PConv,性能远超MobileNet,MobileVit 为了设计快速神经网络,许多工作都专注于减少浮点运算…

高考杂志《高考》杂志社高考杂志社2024年第13期目录

高考论坛 新高考背景下高中生物核心素养培养的策略研究 胡世敏; 3-5《高考》投稿&#xff1a;cn7kantougao163.com 对新高考背景下职业生涯规划教育发展的思考 李昉睿; 6-8 基于新高考的高中语文现代诗歌教学探究 申艳; 9-11 “三新”改革下培养高中生英语核心…

A6110 轴相对振动监控器AMS 6500机械健康监测器

轴相对振动监控器的设计具有极高的可靠性 工厂最重要的旋转机械。此单槽显示器与一起使用 其他AMS 6500监视器构建一个完整的API 670机械保护监视器。 应用包括蒸汽、气体、压缩机和水力涡轮机械。 轴相对振动监控模块的主要功能是 通过比较准确监测轴相对振动并可靠地保护机械…

Vxe UI vue 使用 VxeUI.previewImage() 图片预览方法

Vxe UI vue 使用 VxeUI.previewImage() 图片预览方法的调用 查看 github 代码 调用全局方法 VxeUI.previewImage() 参数说明&#xff1a; urlList&#xff1a;图片列表&#xff0c;支持传字符串&#xff0c;也可以传对象数组 [{url: xx’l}] activeIndex&#xff1a;指定默…

OceanBase 4.3.0 列存引擎解读:OLAP场景的入门券

近期&#xff0c;OceanBase 发布了4.3.0版本&#xff0c;该版本成功实现了行存与列存存储的一体化&#xff0c;并同时推出了基于列存的全新向量化引擎和代价评估模型。通过强化这些能力&#xff0c;OceanBase V4.3.0 显著提高了处理宽表的效率&#xff0c;增强了在AP&#xff0…

excle中数据分析,excle导入用sql简单处理

前言&#xff1a; 办法一&#xff1a;直接用excle导入db就行&#xff0c;如果excle导如db不能用&#xff0c;就用笨办法下面这个方法去做 1、从系统中导出excle 2、db中插入相应的表和标题 3、先手动插入条件&#xff0c;把insert语句复制出来 INSERT INTO test.test (orders…