在UICollectionView中滚动到上一个/下一个图像时,正确计算颜色不透明度偏移以更改背景颜色?

时间:2016-12-20 22:10:49

标签: ios swift uicollectionview swift3

如果标题含糊不清,我很抱歉,但目前我有UICollectionView张图片。我最近发现了一种使用DominantColor找到UIImage的主色的方法。有了这个,我试图改变UICollectionView的背景颜色,因为用户从一个UIImage单元格滚动到下一个单元格,即背景颜色将慢慢从imageX的主色渐变到imageX + 1的主导色。

但是,我已经花了好几天时间而且在更改UICollectionView的背景颜色不透明度时非常困难,因为单元格开始滚动到下一个/上一张图像。

我的用户界面:

enter image description here

背景代码:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as UICollectionViewCell

    let frame: CGRect = CGRect(x: 0, y: 0, width: imageView.frame.size.width, height: imageView.frame.size.height)

    let subView: UIImageView = UIImageView(frame: frame)

    subView.image = imagesArray[indexPath.row].theImage

    subView.contentMode = UIViewContentMode.scaleAspectFit

    cell.addSubview(subView)

    return cell
}

// The colorsArray will contain a dominant color for each image in the CollectionView
func dominantColorOfImages()
{
    for index in 0..<imagesArray.count
    {
        if let image = imagesArray[index].theImage
        {
            let colors: [UIColor] = image.dominantColors()

            colorsArray[index] = colors[index]
        }
    }

    // Default dominant background color for first image in CollectionView
    imagesCollectionView.backgroundColor = colorsArray[0]

    imagesCollectionView.reloadData()
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
{
    let pageWidth: CGFloat = scrollView.bounds.size.width

    let currentPage: Int = Int( floor( (scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)

    currentImagePage = currentPage
}

func scrollViewDidScroll(_ scrollView: UIScrollView)
{
    let pageWidth: CGFloat = scrollView.bounds.size.width
    let currentPage: Int = Int( floor( (scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)

    // Horizontal
    let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.size.width
    let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x


    // This is the offset of how far the right side edge of the current image has pass the end of the left screen (i.e. when the user scrolls the image from the right to the left to get to the next image)
    let pageOffset: CGFloat = ( (pageWidth * CGFloat(currentImagePage) ) + (pageWidth / 2) ) / maximumHorizontalOffset

    if percentageHorizontalOffset < pageOffset
    {

        imagesCollectionView.backgroundColor = fadeFromColorToColor(fromColor: colorsArray[currentImagePage], toColor: colorsArray[currentImagePage + 1], withPercentage: percentageHorizontalOffset * CGFloat(colorsArray.count - 1 ) )

    }
    else
    {

        imagesCollectionView.backgroundColor = fadeFromColorToColor(fromColor: colorsArray[currentImagePage], toColor: colorsArray[currentImagePage + 1], withPercentage: (percentageHorizontalOffset - pageOffset) * CGFloat(colorsArray.count - 1) ))

    }
}

func fadeFromColorToColor(fromColor: UIColor, toColor: UIColor, withPercentage: CGFloat) -> UIColor
{
    var fromRed: CGFloat = 0.0
    var fromGreen: CGFloat = 0.0
    var fromBlue: CGFloat = 0.0
    var fromAlpha: CGFloat = 0.0

    // Get the RGBA values from the colours
    fromColor.getRed(&fromRed, green: &fromGreen, blue: &fromBlue, alpha: &fromAlpha)

    var toRed: CGFloat = 0.0
    var toGreen: CGFloat = 0.0
    var toBlue: CGFloat = 0.0
    var toAlpha: CGFloat = 0.0

    toColor.getRed(&toRed, green: &toGreen, blue: &toBlue, alpha: &toAlpha)

    // Calculate the actual RGBA values of the fade colour
    let red = (toRed - fromRed) * withPercentage + fromRed;
    let green = (toGreen - fromGreen) * withPercentage + fromGreen;
    let blue = (toBlue - fromBlue) * withPercentage + fromBlue;
    let alpha = (toAlpha - fromAlpha) * withPercentage + fromAlpha;

    // Return the fade colour
    return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}

这是遵循此处提供的相同答案:Changing between colors based on UIScrollView's contentOffset,但pageOffset被硬编码为0.5,因为该问题涉及2个静态页面,而我正在处理{{1}页面,所以我不得不重新计算colorsArray.count - 1

我遇到的问题在pageOffset withPercentage {。}}内。

当我从Image1-&gt; Image2开始滚动时,颜色会逐渐消失。但是,一旦Image2停止,背景颜色立即跳转到Image3中的颜色,并输入scrollViewDidScroll语句。

举例说明,这是在iPhone 7模拟器上运行的image1-&gt; image2输出的颜色不透明度:

else

这是我知道我的计算已经完成的地方,但是我正在努力实现这一目标。

3 个答案:

答案 0 :(得分:0)

很难准确读取您的代码示例,因为某些变量/标识符未在示例文本中定义,例如percentageHorizo​​ntalOffset

如果将scrollViewDidScroll func的else子句中的行更改为:

,该怎么办?
var color1 = prompt("Enter first color: yellow, red or blue");
var color2 = prompt("Enter second color: yellow, red or blue"); 

if (color1 == "yellow" && color2 == "yellow"){
      console.log("mixing of these two colors makes yellow");
    }
if (color1 == "red" && color2 == "red"){
      console.log("mixing of these two colors makes red");
    }
if (color1 == "blue" && color2 == "blue"){
      console.log("mixing of these two colors makes blue");
    }
if (color1 == "yellow" && color2 == "red" || color1 == "red" && color2 == "yellow"){
      console.log("mixing of these two colors makes orange");
    }
if (color1 == "yellow" && color2 == "blue" || color1 == "blue" && color2 == "yellow"){
      console.log("mixing of these two colors makes green");
    }
if (color1 == "blue" && color2 == "red" || color1 == "red" && color2 == "blue"){
      console.log("mixing of these two colors makes purple");
    }

答案 1 :(得分:0)

fadeFromColorToColor中,如果百分比为负数,则交换toColorfromColor并转为percent为正。

答案 2 :(得分:0)

这里有一些准备粘贴到游乐场的代码。打开助理编辑器以使用集合视图。那是你在找什么?

import UIKit
import PlaygroundSupport

extension UIColor {
    func components() -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) {
        var r: CGFloat = 0.0
        var g: CGFloat = 0.0
        var b: CGFloat = 0.0
        var a: CGFloat = 0.0
        getRed(&r, green: &g, blue: &b, alpha: &a)
        return (r, g, b, a)
    }
}

class Controller: UICollectionViewController {

    // some test data instead of images:
    let pages = [#colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1), #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1), #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1), #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1), #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)]

    // these should be your significant colors from the images:
    let colorsArray = [#colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1), #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1), #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1), #colorLiteral(red: 0.9568627477, green: 0.6588235497, blue: 0.5450980663, alpha: 1), #colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1), #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1)]

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        collectionView?.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return pages.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = pages[indexPath.item]
        return cell
    }

    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let currentHorizontalOffset = collectionView!.contentOffset.x + collectionView!.contentInset.left
        let pageWidth = scrollView.bounds.size.width
        let page = Int(max(0, floor(currentHorizontalOffset / pageWidth)))

        // Don't change the background color when scrolling past the last page:
        guard page < pages.count - 1 else {
            return
        }

        let partialPageVisibleWidth = currentHorizontalOffset - CGFloat(page) * pageWidth
        let ratio = max(0, partialPageVisibleWidth / pageWidth)

        let leftColor = colorsArray[page]
        let rightColor = colorsArray[page + 1]

        scrollView.backgroundColor = blend(leftColor, rightColor, ratio: ratio)
    }

    /**
    Blends two colors by the given ratio

    - returns: `lhs` if t == 0; `rhs` if t == 1; otherwise a blend of `lhs` and `rhs` by using a linear interpolation function
    */
    func blend(_ lhs: UIColor, _ rhs: UIColor, ratio t: CGFloat) -> UIColor
    {
        let (r1, g1, b1, a1) = lhs.components()
        let (r2, g2, b2, a2) = rhs.components()

        // Interpolation function:
        func f(_ from: CGFloat, _ to: CGFloat) -> CGFloat {
            return from * (1 - t) + to * t
        }

        // create a new color by interpolating two colors:
        return UIColor(
            red:   f(r1, r2),
            green: f(g1, g2),
            blue:  f(b1, b2),
            alpha: f(a2, a2)
        )
    }
}



// Test code:

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 280, height: 400)
layout.minimumLineSpacing = 40

let controller = Controller(collectionViewLayout: layout)
controller.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)

PlaygroundPage.current.liveView = controller.view