react-native 获取某一元素的绝对位置(相对于屏幕左上角)

react-native 获取某一元素的绝对位置(相对于屏幕左上角),第1张

DOM结构:

<View style={stylescheckContainer}  ref='checkContainer' onLayout={({nativeEvent:e})=>thislayout(e)}> 

</View>

对应js方法

layout=(e)=>{

      consolewarn(elayouty)  ;

      var UIManager = require('UIManager');

      consolewarn(etarget);

      UIManagermeasure(etarget, (x, y, width, height, left, top) => {

     consolewarn('x:'+x)

     consolewarn('y:'+y)

     consolewarn('width:'+width)

     consolewarn('height:'+height)

     consolewarn('left:'+left)

     consolewarn('top:'+top)

})

}

注意:View组件的onLayout(可以得到宽高和相对位置)配合UIManagermeasure(可以得到宽高和绝对位置)一起使用

附加知识点:

得到某一dom元素的节点值:

import {findNodeHandle} from 'react-native';

var nodeData = findNodeHandle(thisrefsname);

nodeData即为节点值

用这种方式拾取。。

//-----------------------------------------------------------------------------

// Desc: 拾取三角形

//-----------------------------------------------------------------------------

HRESULT Pick_Triangle(IDirect3DDevice9 pd3dDevice, LPD3DXMESH pMesh)

{

HRESULT hr = S_OK;

g_dwNumIntersections = 0L;

if( !GetCapture() )

return hr;

//计算拾取射线相关变量声明

POINT ptCursor; //鼠标位置

D3DXMATRIX matWorld, matView, pmatProj, m;

D3DXVECTOR3 vPickRayOrig, vPickRayDir;

int iWidth, iHeight;

//获取后台缓冲区的宽度和高度

iWidth = DXUTGetBackBufferSurfaceDesc()->Width;

iHeight = DXUTGetBackBufferSurfaceDesc()->Height;

//获取当前鼠标在窗口客户区中的位置

GetCursorPos( &ptCursor );

ScreenToClient( DXUTGetHWND(), &ptCursor );

//获取当前设备的变换矩阵

pd3dDevice->GetTransform( D3DTS_WORLD, &matWorld );

pd3dDevice->GetTransform( D3DTS_VIEW, &matView );

pd3dDevice->GetTransform( D3DTS_PROJECTION, &pmatProj );

//计算世界观察矩阵的逆矩阵

D3DXMATRIX mWorldView = matWorld matView;

D3DXMatrixInverse( &m, NULL, &mWorldView );

//计算拾取射线的方向与原点

D3DXVECTOR3 vTemp;

vTempx = ((( 20f ptCursorx ) / iWidth ) - 1 ) / pmatProj_11;

vTempy = -((( 20f ptCursory ) / iHeight ) - 1 ) / pmatProj_22;

vTempz = 10f;

vPickRayDirx = vTempxm_11 + vTempym_21 + vTempzm_31;

vPickRayDiry = vTempxm_12 + vTempym_22 + vTempzm_32;

vPickRayDirz = vTempxm_13 + vTempym_23 + vTempzm_33;

vPickRayOrigx = m_41;

vPickRayOrigy = m_42;

vPickRayOrigz = m_43;

//计算被拾取到的三角形, 得到拾取到三角形的索引

BOOL bHit;

LPD3DXBUFFER pBuffer = NULL;

D3DXINTERSECTINFO pIntersectInfoArray;

V_RETURN( D3DXIntersect( pMesh, &vPickRayOrig, &vPickRayDir, &bHit,

NULL, NULL, NULL, NULL,

&pBuffer, &g_dwNumIntersections ));

if( g_dwNumIntersections > 0 )

{

pIntersectInfoArray = (D3DXINTERSECTINFO)pBuffer->GetBufferPointer();

if( g_dwNumIntersections > MAX_INTERSECTIONS )

g_dwNumIntersections = MAX_INTERSECTIONS;

for( DWORD iIntersection = 0; iIntersection < g_dwNumIntersections; iIntersection++ )

{

g_IntersectionArray[iIntersection] = pIntersectInfoArray[iIntersection]FaceIndex;

}

}

SAFE_RELEASE( pBuffer );

//根据拾取到三角形的索引, 将三角形顶点数据添加到g_pVB中

LPDIRECT3DVERTEXBUFFER9 pVB;

LPDIRECT3DINDEXBUFFER9 pIB;

WORD pIndices;

D3DVERTEX pVertices;

pMesh->GetVertexBuffer( &pVB );

pMesh->GetIndexBuffer( &pIB );

pIB->Lock( 0, 0, (void)&pIndices, 0 );

pVB->Lock( 0, 0, (void)&pVertices, 0 );

if( g_dwNumIntersections > 0 )

{

D3DVERTEX v;

D3DVERTEX vThisTri;

WORD iThisTri;

DWORD pIntersection;

g_pVB->Lock( 0, 0, (void)&v, 0 );

for( DWORD iIntersection = 0; iIntersection < g_dwNumIntersections; iIntersection++ )

{

pIntersection = &g_IntersectionArray[iIntersection];

vThisTri = &v[iIntersection 3];

iThisTri = &pIndices[3(pIntersection)];

vThisTri[0] = pVertices[iThisTri[0]];

vThisTri[1] = pVertices[iThisTri[1]];

vThisTri[2] = pVertices[iThisTri[2]];

}

g_pVB->Unlock();

}

pVB->Unlock();

pIB->Unlock();

SAFE_RELEASE(pVB);

SAFE_RELEASE(pIB);

return S_OK;

}

这是AndroidUI绘制流程分析的第二篇文章,主要分析界面中View是如何绘制到界面上的具体过程。

ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和 DecorView 的纽带,View的三大流程均是通过 ViewRoot 来完成的。在 ActivityThread 中,当 Activity 对象被创建完毕后,会将 DecorView 添加到 Window 中,同时会创建 ViewRootImpl 对象,并将 ViewRootImpl 对象和 DecorView 建立关联。

measure 过程决定了 View 的宽/高, Measure 完成以后,可以通过 getMeasuredWidth 和 getMeasuredHeight 方法来获取 View 测量后的宽/高,在几乎所有的情况下,它等同于View的最终的宽/高,但是特殊情况除外。 Layout 过程决定了 View 的四个顶点的坐标和实际的宽/高,完成以后,可以通过 getTop、getBottom、getLeft 和 getRight 来拿到View的四个顶点的位置,可以通过 getWidth 和 getHeight 方法拿到View的最终宽/高。 Draw 过程决定了 View 的显示,只有 draw 方法完成后 View 的内容才能呈现在屏幕上。

DecorView 作为顶级 View ,一般情况下,它内部会包含一个竖直方向的 LinearLayout ,在这个 LinearLayout 里面有上下两个部分,上面是标题栏,下面是内容栏。在Activity中,我们通过 setContentView 所设置的布局文件其实就是被加到内容栏中的,而内容栏id为 content 。可以通过下面方法得到 content:ViewGroup content = findViewById(Randroididcontent) 。通过 contentgetChildAt(0) 可以得到设置的 view 。 DecorView 其实是一个 FrameLayout , View 层的事件都先经过 DecorView ,然后才传递给我们的 View 。

MeasureSpec 代表一个32位的int值,高2位代表 SpecMode ,低30位代表 SpecSize , SpecMode 是指测量模式,而 SpecSize 是指在某种测量模式下的规格大小。

SpecMode 有三类,如下所示:

UNSPECIFIED

EXACTLY

AT_MOST

LayoutParams需要和父容器一起才能决定View的MeasureSpec,从而进一步决定View的宽/高。

对于顶级View,即DecorView和普通View来说,MeasureSpec的转换过程略有不同。对于DecorView,其MeasureSpec由窗口的尺寸和其自身的LayoutParams共同确定;

对于普通View,其MeasureSpec由父容器的MeasureSpec和自身的Layoutparams共同决定;

MeasureSpec一旦确定,onMeasure就可以确定View的测量宽/高。

小结一下

当子 View 的宽高采用 wrap_content 时,不管父容器的模式是精确模式还是最大模式,子 View 的模式总是最大模式+父容器的剩余空间。

View 的工作流程主要是指 measure 、 layout 、 draw 三大流程,即测量、布局、绘制。其中 measure 确定 View 的测量宽/高, layout 确定 view 的最终宽/高和四个顶点的位置,而 draw 则将 View 绘制在屏幕上。

measure 过程要分情况,如果只是一个原始的 view ,则通过 measure 方法就完成了其测量过程,如果是一个 ViewGroup ,除了完成自己的测量过程外,还会遍历调用所有子元素的 measure 方法,各个子元素再递归去执行这个流程。

如果是一个原始的 View,那么通过 measure 方法就完成了测量过程,在 measure 方法中会去调用 View 的 onMeasure 方法,View 类里面定义了 onMeasure 方法的默认实现:

先看一下 getSuggestedMinimumWidth 和 getSuggestedMinimumHeight 方法的源码:

可以看到, getMinimumWidth 方法获取的是 Drawable 的原始宽度。如果存在原始宽度(即满足 intrinsicWidth > 0),那么直接返回原始宽度即可;如果不存在原始宽度(即不满足 intrinsicWidth > 0),那么就返回 0。

接着看最重要的 getDefaultSize 方法:

如果 specMode 为 MeasureSpecUNSPECIFIED 即未指定模式,那么返回由方法参数传递过来的尺寸作为 View 的测量宽度和高度;

如果 specMode 不是 MeasureSpecUNSPECIFIED 即是最大模式或者精确模式,那么返回从 measureSpec 中取出的 specSize 作为 View 测量后的宽度和高度。

看一下刚才的表格:

当 specMode 为 EXACTLY 或者 AT_MOST 时,View 的布局参数为 wrap_content 或者 match_parent 时,给 View 的 specSize 都是 parentSize 。这会比建议的最小宽高要大。这是不符合我们的预期的。因为我们给 View 设置 wrap_content 是希望View的大小刚好可以包裹它的内容。

因此:

如果是一个 ViewGroup,除了完成自己的 measure 过程以外,还会遍历去调用所有子元素的 measure 方法,各个子元素再递归去执行 measure 过程。

ViewGroup 并没有重写 View 的 onMeasure 方法,但是它提供了 measureChildren、measureChild、measureChildWithMargins 这几个方法专门用于测量子元素。

如果是 View 的话,那么在它的 layout 方法中就确定了自身的位置(具体来说是通过 setFrame 方法来设定 View 的四个顶点的位置,即初始化 mLeft , mRight , mTop , mBottom 这四个值), layout 过程就结束了。

如果是 ViewGroup 的话,那么在它的 layout 方法中只是确定了 ViewGroup 自身的位置,要确定子元素的位置,就需要重写 onLayout 方法;在 onLayout 方法中,会调用子元素的 layout 方法,子元素在它的 layout 方法中确定自己的位置,这样一层一层地传递下去完成整个 View 树的 layout 过程。

layout 方法的作用是确定 View 本身的位置,即设定 View 的四个顶点的位置,这样就确定了 View 在父容器中的位置;

onLayout 方法的作用是父容器确定子元素的位置,这个方法在 View 中是空实现,因为 View 没有子元素了,在 ViewGroup 中则进行抽象化,它的子类必须实现这个方法。

1绘制背景( backgrounddraw(canvas); );

2绘制自己( onDraw );

3绘制 children( dispatchDraw(canvas) );

4绘制装饰( onDrawScrollBars )。

dispatchDraw 方法的调用是在 onDraw 方法之后,也就是说,总是先绘制自己再绘制子 View 。

对于 View 类来说, dispatchDraw 方法是空实现的,对于 ViewGroup 类来说, dispatchDraw 方法是有具体实现的。

通过 dispatchDraw 来传递的。 dispatchDraw 会遍历调用子元素的 draw 方法,如此 draw 事件就一层一层传递了下去。dispatchDraw 在 View 类中是空实现的,在 ViewGroup 类中是真正实现的。

如果一个 View 不需要绘制任何内容,那么就设置这个标记为 true,系统会进行进一步的优化。

当创建的自定义控件继承于 ViewGroup 并且不具备绘制功能时,就可以开启这个标记,便于系统进行后续的优化;当明确知道一个 ViewGroup 需要通过 onDraw 绘制内容时,需要关闭这个标记。

参考:《Android开发艺术探索》

以上就是关于react-native 获取某一元素的绝对位置(相对于屏幕左上角)全部的内容,包括:react-native 获取某一元素的绝对位置(相对于屏幕左上角)、关于Directinput的绝对坐标问题、Android UI绘制之View绘制的工作原理等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9573787.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存