[開發者日記] 聊天通訊APP - 限時動態更新(I)

簡介

如果您想了解該項目的內容,請閱讀以下文章。
ChatApp(I)
ChatApp(II)
ChatApp(III)
ChatApp(IV)
ChatApp(V)
ChatApp(VI)

Demo

TODO

在先前的版本中,它確實允許用戶將多個文本添加到他們的限時動態中。但如果不使用眼睛就很難對齊所有文字項目。因此,在這個版本中,我決定添加一個對齊工具來幫助他們,這類似於「Instagram」對齊工具。

如何實作

為了實現這個功能,我們首先需要知道使用者想要對齊的項目的「寬度」和「高度」。由於項目可以縮放旋轉,因此寬度高度會與原始尺寸不同,因此我們需要先獲得正確的尺寸,然後才能開始對齊。

你可能想知道在縮放旋轉之後我們如何才能得到正確的尺寸。對於縮放來說,它比旋轉要容易一些,我們只需要把尺寸乘以比例的factor,就可以得到正確的縮放尺寸。但是要計算旋轉後的大小,我們需要一些數學來幫助我們,這是我們在高中學過的,那就是「三角函數」。應用這個數學,我們可以輕鬆計算寬度高度

math

獲得正確的尺寸後,我們可以開始對齊項目。對齊函數只是一個簡單的計算,所以我不會在這裡分享細節,但我會在這裡提供所有這些函數供您參考!

To calculate the size

GeometryReader{ proxy -> Color in
    DispatchQueue.main.async {
        self.currentItemSize = proxy.size
        let newWidthAfterRotate1 = self.currentItemSize.height * sin(box.angle.radians)
        let newWidthAfterRotate2 = self.currentItemSize.width * cos(box.angle.radians)
        let newHeightAfterRotate1 = self.currentItemSize.height * cos(box.angle.radians)
        let newHeightAfterRotate2 = self.currentItemSize.width * sin(box.angle.radians)
        self.currentItemSize.width = abs(newWidthAfterRotate1) + abs(newWidthAfterRotate2)
        self.currentItemSize.height = abs(newHeightAfterRotate1) + abs(newHeightAfterRotate2)
        self.currentItemSize.width *= (box.scaleFactor + box.lastScaleFactor) //new width after scale
        self.currentItemSize.height *= (box.scaleFactor + box.lastScaleFactor) //new heigh after scale
        //https://i.stack.imgur.com/C6NVo.png
    }
    return Color.clear
}

Alignment functions - Leading Alignment

 private func leadingAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize {
        var location = newLocation
        let startWidth = location.width - (self.currentItemSize.width / 2)
        let leadingAignment = -(proxyFrame.width / 2  - 10)
        
        if !isLeadingAlignment {
            if startWidth >= leadingAignment && startWidth <= leadingAignment + 3{
                withAnimation{
                    isLeadingAlignment = true
                }
            }
        }else {
            //TODO: To leave the alignment status
            if startWidth <= leadingAignment - 10 || startWidth >= leadingAignment + 10{
                withAnimation{
                    isLeadingAlignment = false
                }
            }
        }
        withAnimation{
            location.width = isLeadingAlignment ? leadingAignment + (self.currentItemSize.width / 2) : location.width
        }
        return location
    }

Alignment functions - Traling Alignment

    private func tralingAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize{
        var location = newLocation
        let endWidth = location.width + (self.currentItemSize.width / 2)
        let tralingAignment = proxyFrame.width / 2  - 10
        
        if !isTralingAlignment {
            if endWidth >= tralingAignment && endWidth <= tralingAignment + 3{
                withAnimation{
                    isTralingAlignment = true
                }
            }
        }else {
            //TODO: To leave the alignment status
            if endWidth <= tralingAignment - 10 || endWidth >= tralingAignment + 10{
                withAnimation{
                    isTralingAlignment = false
                }
            }
        }
        withAnimation{
            location.width = isTralingAlignment ? tralingAignment - (self.currentItemSize.width / 2) : location.width
        }
        return location
    }
    

Alignment functions - Top Alignment

    private func topAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize{
        var location = newLocation
        let startHeight = location.height - (self.currentItemSize.height / 2)
        
        let topAignment = -((UIScreen.main.bounds.height / 1.22) / 2 - 50)
        if !isTopAlignment {
            if startHeight >= topAignment && startHeight <= topAignment + 3{
                withAnimation{
                    isTopAlignment = true
                }
            }
        }else {
            //TODO: To leave the alignment status
            if startHeight <= topAignment - 10 || startHeight >= topAignment + 10{
                withAnimation{
                    isTopAlignment = false
                }
            }
        }
        withAnimation{
            location.height = isTopAlignment ? topAignment + (self.currentItemSize.height / 2) : location.height
        }
        return location
    }
    

Alignment functions - Bottom Alignment

    private func bottomAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize{
        var location = newLocation
        let endHeight = location.height + (self.currentItemSize.height / 2)
        
        let bottomAignment = ((UIScreen.main.bounds.height / 1.22) / 2 - 50)
        if !isBottomAlignment {
            if endHeight >= bottomAignment && endHeight <= bottomAignment + 3{
                withAnimation{
                    isBottomAlignment = true
                }
            }
        }else {
            //TODO: To leave the alignment status
            if endHeight <= bottomAignment - 10 || endHeight >= bottomAignment + 10{
                withAnimation{
                    isBottomAlignment = false
                }
            }
        }
        withAnimation{
            location.height = isBottomAlignment ? bottomAignment - (self.currentItemSize.height / 2) : location.height
        }
        return location
    }

Alignment functions - Vertical Alignment

    private func verticalAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize{
        var location = newLocation


        if !isVerticalAlignment {
            if location.height >= 0 && location.height <=  3 {
                withAnimation{
                    isVerticalAlignment = true
                    
                }
            }
        }else {
            //TODO: To leave the alignment status
            if location.height <=  -10 || location.height >=  10{
                withAnimation{
                    isVerticalAlignment = false
                }
            }
        }
        withAnimation{
            location.height = isVerticalAlignment ? 0 : location.height
        }
        return location
    }

Alignment functions - Horizontal Alignment

    private func horizontalAlignmentChecking(proxyFrame : CGSize,newLocation : CGSize) -> CGSize{
        var location = newLocation


        if !isHorizontalAlignment {
            if location.width >= 0 && location.width <=  3 {
                withAnimation{
                    isHorizontalAlignment = true
                }
            }
        }else {
            //TODO: To leave the alignment status
            if location.width <=  -10 || location.width >=  10{
                withAnimation{
                    isHorizontalAlignment = false
                }
            }
        }
        withAnimation(){
            location.width = isHorizontalAlignment ? 0 : location.width
        }
        return location
    }

我的分享到此結束,感謝您的閱讀^^,再見!