代码之家  ›  专栏  ›  技术社区  ›  schmidt9

在superview中定位具有任意定位点的子视图

  •  0
  • schmidt9  · 技术社区  · 7 年前

    我很难想出正确的算法。我有一个超级视图(绿色)和一个子视图(黄色)。具有任意的锚定点(只是一个选择点,不与层的 anchor 属性)在此子视图(红色)中,我必须按照放置此红色点的方式放置子视图并调整其大小 子视图的大小也会随之调整 按比例地 如果需要(如果在移动其帧后超出superview的边界)。没有使用自动布局。看看我想要什么。

    所以基本上我写了一个C++测试例程,其中一个新的比例矩形被计算为“新的点”(因此,这个点得到这个新矩形的中心),但是我不知道接下来要做什么来处理一个不在子视图中心的点。 Rect 基本上是一个具有 x, y, width, height 成员。

        Rect
        calculateRectInBounds(const Rect &boundingRect, const Rect &initialRect, const Point &translationPoint)
        {
            double boundsWidth = boundingRect.getWidth();
            double boundsHeight = boundingRect.getHeight();
            double distanceX, distanceY;
            Size sizeByWidth, sizeByHeight;
    
            // detect part where point is
    
            /*
             * UL | UR
             * ---C---
             * LL | LR
             */
    
            // -- upper left - check left & top borders
    
            if (translationPoint.x <= boundsWidth / 2 && translationPoint.y < boundsHeight / 2) {
                distanceX = translationPoint.x;
                distanceY = translationPoint.y;
    
                sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
                sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);
    
                if (sizeByWidth.height > distanceY) {
                    return {translationPoint.x - sizeByHeight.width,
                            0,
                            sizeByHeight.width * 2,
                            sizeByHeight.height * 2};
                }
    
                return {0,
                        translationPoint.y - sizeByWidth.height,
                        sizeByWidth.width * 2,
                        sizeByWidth.height * 2};
            }
    
            // -- upper right - check top & right borders
    
            if (translationPoint.x > boundsWidth / 2 && translationPoint.y <= boundsHeight / 2) {
                distanceX = boundsWidth - translationPoint.x;
                distanceY = translationPoint.y;
    
                sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
                sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);
    
                if (sizeByWidth.height > distanceY) {
                    return {translationPoint.x - sizeByHeight.width,
                            0,
                            sizeByHeight.width * 2,
                            sizeByHeight.height * 2};
                }
    
                return {translationPoint.x - sizeByWidth.width,
                        translationPoint.y - sizeByWidth.height,
                        sizeByWidth.width * 2,
                        sizeByWidth.height * 2};
            }
    
            // -- lower right - check right & bottom borders
    
            if (translationPoint.x >= boundsWidth / 2 && translationPoint.y > boundsHeight / 2) {
                distanceX = boundsWidth - translationPoint.x;
                distanceY = boundsHeight - translationPoint.y;
    
                sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
                sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);
    
                if (sizeByWidth.height > distanceY) {
                    return {translationPoint.x - sizeByHeight.width,
                            translationPoint.y - sizeByHeight.height,
                            sizeByHeight.width * 2,
                            sizeByHeight.height * 2};
                }
    
                return {translationPoint.x - sizeByWidth.width,
                        translationPoint.y - sizeByWidth.height,
                        sizeByWidth.width * 2,
                        sizeByWidth.height * 2};
            }
    
            // -- lower left - check bottom & left borders
    
            if (translationPoint.x < boundsWidth / 2 && translationPoint.y >= boundsHeight / 2) {
                distanceX = translationPoint.x;
                distanceY = boundsHeight - translationPoint.y;
    
                sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
                sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);
    
                if (sizeByWidth.height > distanceY) {
                    return {translationPoint.x - sizeByHeight.width,
                            translationPoint.y - sizeByHeight.height,
                            sizeByHeight.width * 2,
                            sizeByHeight.height * 2};
                }
    
                return {0,
                        translationPoint.y - sizeByWidth.height,
                        sizeByWidth.width * 2,
                        sizeByWidth.height * 2};
            }
    
            // -- center
    
            return initialRect;
        }
    
    Size
    scaleSizeToWidth(Size size, double newWidth)
    {
        return {newWidth, (std::min(size.width, newWidth) / std::max(size.width, newWidth)) * size.height};
    }
    
    Size
    scaleSizeToHeight(Size size, double newHeight)
    {
        return {(std::min(size.height, newHeight) / std::max(size.height, newHeight)) * size.width, newHeight};
    }
    

    enter image description here

        Rect
        calculateRectInBounds(const Rect &boundingRect, const Rect &initialRect, const Point &anchorPoint)
        {
            auto lDist = anchorPoint.x - initialRect.getX();
            auto rDist = initialRect.getWidth() - lDist;
            auto tDist = anchorPoint.y - initialRect.getY();
            auto bDist = initialRect.getHeight() - tDist;
    
            auto lRatio = (lDist * 2) / boundingRect.getWidth();
            auto rRatio = (rDist * 2) / boundingRect.getWidth();
            auto tRatio = (tDist * 2) / boundingRect.getHeight();
            auto bRatio = (bDist * 2) / boundingRect.getHeight();
    
            auto scale = 1 / std::max({lRatio, rRatio, tRatio, bRatio});
    
            auto x = initialRect.getWidth() / 2 - lDist * scale + initialRect.getX();
            auto y = initialRect.getHeight() / 2 - tDist * scale + initialRect.getY();
            auto width = initialRect.getWidth() * scale;
            auto height = initialRect.getHeight() * scale;
    
            return {x, y, width, height};
        }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   MBo    7 年前

    获取从红点到子视图矩形的所有边的距离

    RedX, YellowWidth-RedX, RedY, YellowHeight - RedY
    

    L = (2 * RedX) / GreenWidth
    R = (2 * (YellowWidth-RedX)) / GreenWidth
    T = (2 * RedY) / GreenHeight
    B = (2 * (YellowHeight-RedY)) / GreenHeight
    

    然后找出其中的最大值

    Mx = Max(L,R,T,B)
    

    现在确定比例:

    Scale = 1 / Mx 
    

    新的子视图坐标:

    X =  YellowWidth / 2  - (RedX * Scale)
    Y =  YellowHeight / 2  - (RedY * Scale)