博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android根据座标找到对应的View
阅读量:2352 次
发布时间:2019-05-10

本文共 2606 字,大约阅读时间需要 8 分钟。

在界面上点击按钮时,想想安卓是如何找到能响应事件的顶层View的?

如果给你坐标x、y, 你能找到对应的顶层View么?

首先安卓布局根节点是DecorView,并呈现为多叉树结构; 每个顶层View都是一个叶节点;

需求:手指在界面上滑动时显示对应的顶层View。

在这里插入图片描述

Activity显示在屏幕上时, 以DecorView为根节点并呈现多叉树数据结构;

在这里插入图片描述

背景知识:

安卓事件分发时从最后一个子节点开始传递事件, 原因是什么呢?
ViewGroup.java的dispatchTouchEvent函数在遍历子View时, 是从最后一个子View开始分发事件的, 详见第2629行;
在这里插入图片描述
常用安卓ViewGroup为LinearLayout、FrameLayout和RelativeLayout, 如果当前ViewGroup是LinearLayout从前向后遍历也行; 但如果是FrameLayout或RelativeLayout就必须从后向前遍历,因为后边的子View可以覆盖前面的子View;

对于Android界面可以从DecorView开始查找, 如果坐标x,y在控件矩形范围内则继续向下递归,为了找到叶节点(即最上面的View)需要深度优先;

public class MainActivity extends AppCompatActivity {    private TextView mTvInfo;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTvInfo = findViewById(R.id.tv_info);    }    @Override public boolean onTouchEvent(MotionEvent event) {        showWidgetInfo(event.getX(), event.getY());        return super.onTouchEvent(event);    }    private void showWidgetInfo(float x, float y) {        View view = getViewByPosition(getWindow().getDecorView(), (int)x, (int)y);        if (view != null) {            mTvInfo.setText(view.toString());        } else {            mTvInfo.setText("没找到匹配的View");        }    }    private View getViewByPosition(View view, int x,  int y) {        if (view == null) {            return null;        }        int[] location = new int[2];        view.getLocationInWindow(location);        int left = location[0];        int top  = location[1];        int right = left + view.getWidth();        int bottom = top + view.getHeight();        if (view instanceof ViewGroup) { //当前是ViewGroup容器            int childCount = ((ViewGroup)view).getChildCount();            //深度优先, 从最后一个子节点开始遍历,如果找到则返回。 先递归判断子View            if (childCount > 0) {                for (int i = childCount - 1; i >= 0; i--) {                    View topView = getViewByPosition(((ViewGroup)view).getChildAt(i), x, y);                    if (topView != null) {                        return topView;                    }                }            }            //子View都没找到匹配的, 再判断自己            if (left < x && top < y && right > x && bottom > y) {                return view;   //当前ViewGroup就是顶层View            } else {                return null; //没找到匹配的            }        } else { //当前是View            if (left < x && top < y && right > x && bottom > y) {                return view;   //当前ViewGroup就是顶层View            } else {                return null; //没找到匹配的            }        }    }}

转载地址:http://gzqvb.baihongyu.com/

你可能感兴趣的文章
logstash 6.x 收集syslog日志
查看>>
Apche Kylin启动报错:UnknownHostException: node1:2181: invalid IPv6 address
查看>>
Apache Kylin 2.3 构建Cube失败
查看>>
Apache Kylin 2.3 样例分析
查看>>
Apache Kylin 2.3 JDBC Java API 示例
查看>>
An internal error occurred during: "Initializing Java Tooling". java.lang.NullPointerException
查看>>
ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
查看>>
IntelliJ IDEA 2018 基本配置
查看>>
Spring+Mybatis+多数据源(MySQL+Oracle)
查看>>
Mybatis读取Oracle数据库Blob字段,输出原文件
查看>>
信用卡反欺诈
查看>>
线性回归
查看>>
浏览器以只读方式打开PDF
查看>>
CDH和HDP下载地址
查看>>
MysqlDataTruncation: Data truncation: Incorrect string value: '\xF0\x9D\x90\xB6"#...' for column
查看>>
.MysqlDataTruncation: Data truncation: Data too long for column 'content' at row 1
查看>>
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1146177 > 1048576).
查看>>
Elasticsearch 7.x生产配置
查看>>
AccessDeniedException: /opt/elasticsearch-7.0.0/config/elasticsearch.keystore
查看>>
bootstrap-table 父子表 联动表 完整例子
查看>>