欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS开发swift 图片轮播功能实现方法

程序员文章站 2022-05-04 09:26:12
自定义创建轮播(第一步) import foundation import uikit import quartzcore import coregraphics import acce...

自定义创建轮播(第一步)

import foundation
import uikit
import quartzcore
import coregraphics
import accelerate


public enum uiimagecontentmode {
    case scaletofill, scaleaspectfit, scaleaspectfill
}

public extension uiimage {

    /**
     a singleton shared nsurl cache used for images from url
     */
    static var shared: nscache! {
        struct staticsharedcache {
            static var shared: nscache? = nscache()
        }

        return staticsharedcache.shared!
    }

    // mark: image from solid color
    /**
     creates a new solid color image.

     - parameter color: the color to fill the image with.
     - parameter size: image size (defaults: 10x10)

     - returns a new image
     */
    convenience init?(color: uicolor, size: cgsize = cgsize(width: 10, height: 10)) {
        let rect = cgrect(x: 0, y: 0, width: size.width, height: size.height)
        uigraphicsbeginimagecontextwithoptions(rect.size, false, 0)

        let context = uigraphicsgetcurrentcontext()
        context?.setfillcolor(color.cgcolor)
        context?.fill(rect)

        self.init(cgimage:(uigraphicsgetimagefromcurrentimagecontext()?.cgimage!)!)
        uigraphicsendimagecontext()
    }

    // mark: image from gradient colors
    /**
     creates a gradient color image.

     - parameter gradientcolors: an array of colors to use for the gradient.
     - parameter size: image size (defaults: 10x10)

     - returns a new image
     */
    convenience init?(gradientcolors:[uicolor], size:cgsize = cgsize(width: 10, height: 10), locations: [float] = [] )
    {
        uigraphicsbeginimagecontextwithoptions(size, false, 0)
        let context = uigraphicsgetcurrentcontext()

        let colorspace = cgcolorspacecreatedevicergb()
        let colors = gradientcolors.map {(color: uicolor) -> anyobject! in return color.cgcolor as anyobject! } as nsarray
        let gradient: cggradient
        if locations.count > 0 {
          let cglocations = locations.map { cgfloat($0) }
          gradient = cggradient(colorsspace: colorspace, colors: colors, locations: cglocations)!
        } else {
          gradient = cggradient(colorsspace: colorspace, colors: colors, locations: nil)!
        }
        context!.drawlineargradient(gradient, start: cgpoint(x: 0, y: 0), end: cgpoint(x: 0, y: size.height), options: cggradientdrawingoptions(rawvalue: 0))
        self.init(cgimage:(uigraphicsgetimagefromcurrentimagecontext()?.cgimage!)!)
        uigraphicsendimagecontext()
    }

    /**
     applies gradient color overlay to an image.

     - parameter gradientcolors: an array of colors to use for the gradient.
     - parameter locations: an array of locations to use for the gradient.
     - parameter blendmode: the blending type to use.

     - returns a new image
     */
    func apply(gradientcolors: [uicolor], locations: [float] = [], blendmode: cgblendmode = cgblendmode.normal) -> uiimage
    {
      uigraphicsbeginimagecontextwithoptions(size, false, scale)
      let context = uigraphicsgetcurrentcontext()
      context?.translateby(x: 0, y: size.height)
      context?.scaleby(x: 1.0, y: -1.0)
      context?.setblendmode(blendmode)
      let rect = cgrect(x: 0, y: 0, width: size.width, height: size.height)

      context?.draw(self.cgimage!, in: rect)
      // create gradient
      let colorspace = cgcolorspacecreatedevicergb()
      let colors = gradientcolors.map {(color: uicolor) -> anyobject! in return color.cgcolor as anyobject! } as nsarray
      let gradient: cggradient
      if locations.count > 0 {
        let cglocations = locations.map { cgfloat($0) }
        gradient = cggradient(colorsspace: colorspace, colors: colors, locations: cglocations)!
      } else {
        gradient = cggradient(colorsspace: colorspace, colors: colors, locations: nil)!
      }
      // apply gradient
      context?.clip(to: rect, mask: self.cgimage!)
      context?.drawlineargradient(gradient, start: cgpoint(x: 0, y: 0), end: cgpoint(x: 0, y: size.height), options: cggradientdrawingoptions(rawvalue: 0))
      let image = uigraphicsgetimagefromcurrentimagecontext()
      uigraphicsendimagecontext();
      return image!;
    }

    // mark: image with text
    /**
     creates a text label image.

     - parameter text: the text to use in the label.
     - parameter font: the font (default: system font of size 18)
     - parameter color: the text color (default: white)
     - parameter backgroundcolor: the background color (default:gray).
     - parameter size: image size (default: 10x10)
     - parameter offset: center offset (default: 0x0)

     - returns a new image
     */
    convenience init?(text: string, font: uifont = uifont.systemfont(ofsize: 18), color: uicolor = uicolor.white, backgroundcolor: uicolor = uicolor.gray, size: cgsize = cgsize(width: 100, height: 100), offset: cgpoint = cgpoint(x: 0, y: 0)) {
        let label = uilabel(frame: cgrect(x: 0, y: 0, width: size.width, height: size.height))
        label.font = font
        label.text = text
        label.textcolor = color
        label.textalignment = .center
        label.backgroundcolor = backgroundcolor

        let image = uiimage(fromview: label)
        uigraphicsbeginimagecontextwithoptions(size, false, 0)
        image?.draw(in: cgrect(x: 0, y: 0, width: size.width, height: size.height))

        self.init(cgimage:(uigraphicsgetimagefromcurrentimagecontext()?.cgimage!)!)
        uigraphicsendimagecontext()
    }

    // mark: image from uiview
    /**
     creates an image from a uiview.

     - parameter fromview: the source view.

     - returns a new image
     */
    convenience init?(fromview view: uiview) {
        uigraphicsbeginimagecontextwithoptions(view.bounds.size, false, 0)
        //view.drawviewhierarchyinrect(view.bounds, afterscreenupdates: true)
        view.layer.render(in: uigraphicsgetcurrentcontext()!)
        self.init(cgimage:(uigraphicsgetimagefromcurrentimagecontext()?.cgimage!)!)
        uigraphicsendimagecontext()
    }

    // mark: image with radial gradient
    // radial background originally from: https://developer.apple.com/library/ios/#documentation/graphicsimaging/conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html
    /**
     creates a radial gradient.

     - parameter startcolor: the start color
     - parameter endcolor: the end color
     - parameter radialgradientcenter: the gradient center (default:0.5,0.5).
     - parameter radius: radius size (default: 0.5)
     - parameter size: image size (default: 100x100)

     - returns a new image
     */
    convenience init?(startcolor: uicolor, endcolor: uicolor, radialgradientcenter: cgpoint = cgpoint(x: 0.5, y: 0.5), radius: float = 0.5, size: cgsize = cgsize(width: 100, height: 100)) {
        uigraphicsbeginimagecontextwithoptions(size, true, 0)

        let num_locations: int = 2
        let locations: [cgfloat] = [0.0, 1.0] as [cgfloat]

        let startcomponents = startcolor.cgcolor.components!
        let endcomponents = endcolor.cgcolor.components!

        let components: [cgfloat] = [startcomponents[0], startcomponents[1], startcomponents[2], startcomponents[3], endcomponents[0], endcomponents[1], endcomponents[2], endcomponents[3]]

        let colorspace = cgcolorspacecreatedevicergb()
        let gradient = cggradient(colorspace: colorspace, colorcomponents: components, locations: locations, count: num_locations)

        // normalize the 0-1 ranged inputs to the width of the image
        let acenter = cgpoint(x: radialgradientcenter.x * size.width, y: radialgradientcenter.y * size.height)
        let aradius = cgfloat(min(size.width, size.height)) * cgfloat(radius)

        // draw it
        uigraphicsgetcurrentcontext()?.drawradialgradient(gradient!, startcenter: acenter, startradius: 0, endcenter: acenter, endradius: aradius, options: cggradientdrawingoptions.drawsafterendlocation)
        self.init(cgimage:(uigraphicsgetimagefromcurrentimagecontext()?.cgimage!)!)

        // clean up
        uigraphicsendimagecontext()
    }

    // mark: alpha
    /**
     returns true if the image has an alpha layer.
     */
    var hasalpha: bool {
        let alpha: cgimagealphainfo = self.cgimage!.alphainfo
        switch alpha {
        case .first, .last, .premultipliedfirst, .premultipliedlast:
            return true
        default:
            return false
        }
    }

    /**
     returns a copy of the given image, adding an alpha channel if it doesn't already have one.
     */
    func applyalpha() -> uiimage? {
        if hasalpha {
            return self
        }

        let imageref = self.cgimage;
        let width = imageref?.width;
        let height = imageref?.height;
        let colorspace = imageref?.colorspace

        // the bitspercomponent and bitmapinfo values are hard-coded to prevent an "unsupported parameter combination" error
        let bitmapinfo = cgbitmapinfo(rawvalue: cgbitmapinfo().rawvalue | cgimagealphainfo.premultipliedfirst.rawvalue)
        let offscreencontext = cgcontext(data: nil, width: width!, height: height!, bitspercomponent: 8, bytesperrow: 0, space: colorspace!, bitmapinfo: bitmapinfo.rawvalue)

        // draw the image into the context and retrieve the new image, which will now have an alpha layer
        let rect: cgrect = cgrect(x: 0, y: 0, width: cgfloat(width!), height: cgfloat(height!))
        offscreencontext?.draw(imageref!, in: rect)
        let imagewithalpha = uiimage(cgimage: (offscreencontext?.makeimage()!)!)
        return imagewithalpha
    }

    /**
     returns a copy of the image with a transparent border of the given size added around its edges. i.e. for rotating an image without getting jagged edges.

     - parameter padding: the padding amount.

     - returns a new image.
     */
    func apply(padding: cgfloat) -> uiimage? {
        // if the image does not have an alpha layer, add one
        let image = self.applyalpha()
        if image == nil {
            return nil
        }
        let rect = cgrect(x: 0, y: 0, width: size.width + padding * 2, height: size.height + padding * 2)

        // build a context that's the same dimensions as the new size
        let colorspace = self.cgimage?.colorspace
        let bitmapinfo = self.cgimage?.bitmapinfo
        let bitspercomponent = self.cgimage?.bitspercomponent
        let context = cgcontext(data: nil, width: int(rect.size.width), height: int(rect.size.height), bitspercomponent: bitspercomponent!, bytesperrow: 0, space: colorspace!, bitmapinfo: (bitmapinfo?.rawvalue)!)

        // draw the image in the center of the context, leaving a gap around the edges
        let imagelocation = cgrect(x: padding, y: padding, width: image!.size.width, height: image!.size.height)
        context?.draw(self.cgimage!, in: imagelocation)

        // create a mask to make the border transparent, and combine it with the image
        let transparentimage = uiimage(cgimage: (context?.makeimage()?.masking(imageref(withpadding: padding, size: rect.size))!)!)
        return transparentimage
    }

    /**
     creates a mask that makes the outer edges transparent and everything else opaque. the size must include the entire mask (opaque part + transparent border).

     - parameter padding: the padding amount.
     - parameter size: the size of the image.

     - returns a core graphics image ref
     */
    fileprivate func imageref(withpadding padding: cgfloat, size: cgsize) -> cgimage {
        // build a context that's the same dimensions as the new size
        let colorspace = cgcolorspacecreatedevicegray()
        let bitmapinfo = cgbitmapinfo(rawvalue: cgbitmapinfo().rawvalue | cgimagealphainfo.none.rawvalue)
        let context = cgcontext(data: nil, width: int(size.width), height: int(size.height), bitspercomponent: 8, bytesperrow: 0, space: colorspace, bitmapinfo: bitmapinfo.rawvalue)

        // start with a mask that's entirely transparent
        context?.setfillcolor(uicolor.black.cgcolor)
        context?.fill(cgrect(x: 0, y: 0, width: size.width, height: size.height))

        // make the inner part (within the border) opaque
        context?.setfillcolor(uicolor.white.cgcolor)
        context?.fill(cgrect(x: padding, y: padding, width: size.width - padding * 2, height: size.height - padding * 2))

        // get an image of the context
        let maskimageref = context?.makeimage()
        return maskimageref!
    }


    // mark: crop

    /**
     creates a cropped copy of an image.

     - parameter bounds: the bounds of the rectangle inside the image.

     - returns a new image
     */
    func crop(bounds: cgrect) -> uiimage? {
        return uiimage(cgimage: (self.cgimage?.cropping(to: bounds)!)!,
                       scale: 0.0, orientation: self.imageorientation)
    }

    func croptosquare() -> uiimage? {
        let size = cgsize(width: self.size.width * self.scale, height: self.size.height * self.scale)
        let shortest = min(size.width, size.height)

        let left: cgfloat = (size.width > shortest) ? (size.width - shortest) / 2 : 0
        let top: cgfloat = (size.height > shortest) ? (size.height - shortest) / 2 : 0

        let rect = cgrect(x: 0, y: 0, width: size.width, height: size.height)
        let insetrect = rect.insetby(dx: left, dy: top)

        return crop(bounds: insetrect)
    }

    // mark: resize

    /**
     creates a resized copy of an image.

     - parameter size: the new size of the image.
     - parameter contentmode: the way to handle the content in the new size.

     - returns a new image
     */
    func resize(tosize: cgsize, contentmode: uiimagecontentmode = .scaletofill) -> uiimage? {
        let horizontalratio = size.width / self.size.width;
        let verticalratio = size.height / self.size.height;
        var ratio: cgfloat!

        switch contentmode {
        case .scaletofill:
            ratio = 1
        case .scaleaspectfill:
            ratio = max(horizontalratio, verticalratio)
        case .scaleaspectfit:
            ratio = min(horizontalratio, verticalratio)
        }

        let rect = cgrect(x: 0, y: 0, width: size.width * ratio, height: size.height * ratio)

        // fix for a colorspace / transparency issue that affects some types of
        // images. see here: https://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/comment-page-2/#comment-39951

        let colorspace = cgcolorspacecreatedevicergb()
        let bitmapinfo = cgbitmapinfo(rawvalue: cgimagealphainfo.premultipliedlast.rawvalue)
        let context = cgcontext(data: nil, width: int(rect.size.width), height: int(rect.size.height), bitspercomponent: 8, bytesperrow: 0, space: colorspace, bitmapinfo: bitmapinfo.rawvalue)

        let transform = cgaffinetransform.identity

        // rotate and/or flip the image if required by its orientation
        context?.concatenate(transform);

        // set the quality level to use when rescaling
        context!.interpolationquality = cginterpolationquality(rawvalue: 3)!

        //cgcontextsetinterpolationquality(context, cginterpolationquality(kcginterpolationhigh.value))

        // draw into the context; this scales the image
        context?.draw(self.cgimage!, in: rect)

        // get the resized image from the context and a uiimage
        let newimage = uiimage(cgimage: (context?.makeimage()!)!, scale: self.scale, orientation: self.imageorientation)
        return newimage;
    }


    // mark: corner radius

    /**
     creates a new image with rounded corners.

     - parameter cornerradius: the corner radius.

     - returns a new image
     */
    func roundcorners(cornerradius: cgfloat) -> uiimage? {
        // if the image does not have an alpha layer, add one
        let imagewithalpha = applyalpha()
        if imagewithalpha == nil {
            return nil
        }

        uigraphicsbeginimagecontextwithoptions(size, false, 0)
        let width = imagewithalpha?.cgimage?.width
        let height = imagewithalpha?.cgimage?.height
        let bits = imagewithalpha?.cgimage?.bitspercomponent
        let colorspace = imagewithalpha?.cgimage?.colorspace
        let bitmapinfo = imagewithalpha?.cgimage?.bitmapinfo
        let context = cgcontext(data: nil, width: width!, height: height!, bitspercomponent: bits!, bytesperrow: 0, space: colorspace!, bitmapinfo: (bitmapinfo?.rawvalue)!)
        let rect = cgrect(x: 0, y: 0, width: cgfloat(width!)*scale, height: cgfloat(height!)*scale)

        context?.beginpath()
        if (cornerradius == 0) {
            context?.addrect(rect)
        } else {
            context?.savegstate()
            context?.translateby(x: rect.minx, y: rect.miny)
            context?.scaleby(x: cornerradius, y: cornerradius)
            let fw = rect.size.width / cornerradius
            let fh = rect.size.height / cornerradius
            context?.move(to: cgpoint(x: fw, y: fh/2))
            context?.addarc(tangent1end: cgpoint(x: fw, y: fh), tangent2end: cgpoint(x: fw/2, y: fh), radius: 1)
            context?.addarc(tangent1end: cgpoint(x: 0, y: fh), tangent2end: cgpoint(x: 0, y: fh/2), radius: 1)
            context?.addarc(tangent1end: cgpoint(x: 0, y: 0), tangent2end: cgpoint(x: fw/2, y: 0), radius: 1)
            context?.addarc(tangent1end: cgpoint(x: fw, y: 0), tangent2end: cgpoint(x: fw, y: fh/2), radius: 1)
            context?.restoregstate()
        }
        context?.closepath()
        context?.clip()

        context?.draw(imagewithalpha!.cgimage!, in: rect)
        let image = uiimage(cgimage: (context?.makeimage()!)!, scale:scale, orientation: .up)
        uigraphicsendimagecontext()
        return image
    }

    /**
     creates a new image with rounded corners and border.

     - parameter cornerradius: the corner radius.
     - parameter border: the size of the border.
     - parameter color: the color of the border.

     - returns a new image
     */
    func roundcorners(cornerradius: cgfloat, border: cgfloat, color: uicolor) -> uiimage? {
        return roundcorners(cornerradius: cornerradius)?.apply(border: border, color: color)
    }

    /**
     creates a new circle image.

     - returns a new image
     */
    func roundcornerstocircle() -> uiimage? {
        let shortest = min(size.width, size.height)
        return croptosquare()?.roundcorners(cornerradius: shortest/2)
    }

    /**
     creates a new circle image with a border.

     - parameter border :cgfloat the size of the border.
     - parameter color :uicolor the color of the border.

     - returns uiimage?
     */
    func roundcornerstocircle(withborder border: cgfloat, color: uicolor) -> uiimage? {
        let shortest = min(size.width, size.height)
        return croptosquare()?.roundcorners(cornerradius: shortest/2, border: border, color: color)
    }

    // mark: border

    /**
     creates a new image with a border.

     - parameter border: the size of the border.
     - parameter color: the color of the border.

     - returns a new image
     */
    func apply(border: cgfloat, color: uicolor) -> uiimage? {
        uigraphicsbeginimagecontextwithoptions(size, false, 0)
        let width = self.cgimage?.width
        let height = self.cgimage?.height
        let bits = self.cgimage?.bitspercomponent
        let colorspace = self.cgimage?.colorspace
        let bitmapinfo = self.cgimage?.bitmapinfo
        let context = cgcontext(data: nil, width: width!, height: height!, bitspercomponent: bits!, bytesperrow: 0, space: colorspace!, bitmapinfo: (bitmapinfo?.rawvalue)!)
        var red: cgfloat = 0, green: cgfloat = 0, blue: cgfloat = 0, alpha: cgfloat = 0
        color.getred(&red, green: &green, blue: &blue, alpha: &alpha)

        context?.setstrokecolor(red: red, green: green, blue: blue, alpha: alpha)
        context?.setlinewidth(border)

        let rect = cgrect(x: 0, y: 0, width: size.width*scale, height: size.height*scale)
        let inset = rect.insetby(dx: border*scale, dy: border*scale)

        context?.strokeellipse(in: inset)
        context?.draw(self.cgimage!, in: inset)

        let image = uiimage(cgimage: (context?.makeimage()!)!)
        uigraphicsendimagecontext()

        return image
    }

    // mark: image effects

    /**
     applies a light blur effect to the image

     - returns new image or nil
     */
    func applylighteffect() -> uiimage? {
        return applyblur(withradius: 30, tintcolor: uicolor(white: 1.0, alpha: 0.3), saturationdeltafactor: 1.8)
    }

    /**
     applies a extra light blur effect to the image

     - returns new image or nil
     */
    func applyextralighteffect() -> uiimage? {
        return applyblur(withradius: 20, tintcolor: uicolor(white: 0.97, alpha: 0.82), saturationdeltafactor: 1.8)
    }

    /**
     applies a dark blur effect to the image

     - returns new image or nil
     */
    func applydarkeffect() -> uiimage? {
        return applyblur(withradius: 20, tintcolor: uicolor(white: 0.11, alpha: 0.73), saturationdeltafactor: 1.8)
    }

    /**
     applies a color tint to an image

     - parameter color: the tint color

     - returns new image or nil
     */
    func applytinteffect(tintcolor: uicolor) -> uiimage? {
        let effectcoloralpha: cgfloat = 0.6
        var effectcolor = tintcolor
        let componentcount = tintcolor.cgcolor.numberofcomponents
        if componentcount == 2 {
            var b: cgfloat = 0
            if tintcolor.getwhite(&b, alpha: nil) {
                effectcolor = uicolor(white: b, alpha: effectcoloralpha)
            }
        } else {
            var red: cgfloat = 0
            var green: cgfloat = 0
            var blue: cgfloat = 0

            if tintcolor.getred(&red, green: &green, blue: &blue, alpha: nil) {
                effectcolor = uicolor(red: red, green: green, blue: blue, alpha: effectcoloralpha)
            }
        }
        return applyblur(withradius: 10, tintcolor: effectcolor, saturationdeltafactor: -1.0)
    }

    /**
     applies a blur to an image based on the specified radius, tint color saturation and mask image

     - parameter blurradius: the radius of the blur.
     - parameter tintcolor: the optional tint color.
     - parameter saturationdeltafactor: the detla for saturation.
     - parameter maskimage: the optional image for masking.

     - returns new image or nil
     */
    func applyblur(withradius blurradius: cgfloat, tintcolor: uicolor?, saturationdeltafactor: cgfloat, maskimage: uiimage? = nil) -> uiimage? {
        guard size.width > 0 && size.height > 0 && cgimage != nil else {
            return nil
        }
        if maskimage != nil {
            guard maskimage?.cgimage != nil else {
                return nil
            }
        }
        let imagerect = cgrect(origin: cgpoint.zero, size: size)
        var effectimage = self
        let hasblur = blurradius > cgfloat(flt_epsilon)
        let hassaturationchange = fabs(saturationdeltafactor - 1.0) > cgfloat(flt_epsilon)
        if (hasblur || hassaturationchange) {

            uigraphicsbeginimagecontextwithoptions(size, false, 0.0)
            let effectincontext = uigraphicsgetcurrentcontext()
            effectincontext?.scaleby(x: 1.0, y: -1.0)
            effectincontext?.translateby(x: 0, y: -size.height)
            effectincontext?.draw(cgimage!, in: imagerect)

            var effectinbuffer = vimage_buffer(
                data: effectincontext?.data,
                height: uint((effectincontext?.height)!),
                width: uint((effectincontext?.width)!),
                rowbytes: (effectincontext?.bytesperrow)!)

            uigraphicsbeginimagecontextwithoptions(size, false, 0.0);
            let effectoutcontext = uigraphicsgetcurrentcontext()

            var effectoutbuffer = vimage_buffer(
                data: effectoutcontext?.data,
                height: uint((effectoutcontext?.height)!),
                width: uint((effectoutcontext?.width)!),
                rowbytes: (effectoutcontext?.bytesperrow)!)

            if hasblur {
                let inputradius = blurradius * uiscreen.main.scale
                let sqrtpi: cgfloat = cgfloat(sqrt(m_pi * 2.0))
                var radius = uint32(floor(inputradius * 3.0 * sqrtpi / 4.0 + 0.5))
                if radius % 2 != 1 {
                    radius += 1 // force radius to be odd so that the three box-blur methodology works.
                }
                let imageedgeextendflags = vimage_flags(kvimageedgeextend)
                vimageboxconvolve_argb8888(&effectinbuffer, &effectoutbuffer, nil, 0, 0, radius, radius, nil, imageedgeextendflags)
                vimageboxconvolve_argb8888(&effectoutbuffer, &effectinbuffer, nil, 0, 0, radius, radius, nil, imageedgeextendflags)
                vimageboxconvolve_argb8888(&effectinbuffer, &effectoutbuffer, nil, 0, 0, radius, radius, nil, imageedgeextendflags)
            }

            var effectimagebuffersareswapped = false

            if hassaturationchange {
                let s: cgfloat = saturationdeltafactor
                let floatingpointsaturationmatrix: [cgfloat] = [
                    0.0722 + 0.9278 * s,  0.0722 - 0.0722 * s,  0.0722 - 0.0722 * s,  0,
                    0.7152 - 0.7152 * s,  0.7152 + 0.2848 * s,  0.7152 - 0.7152 * s,  0,
                    0.2126 - 0.2126 * s,  0.2126 - 0.2126 * s,  0.2126 + 0.7873 * s,  0,
                    0,                    0,                    0,  1
                ]

                let pisor: cgfloat = 256
                let matrixsize = floatingpointsaturationmatrix.count
                var saturationmatrix = [int16](repeating: 0, count: matrixsize)

                for i: int in 0 ..< matrixsize {
                    saturationmatrix[i] = int16(round(floatingpointsaturationmatrix[i] * pisor))
                }

                if hasblur {
                    vimagematrixmultiply_argb8888(&effectoutbuffer, &effectinbuffer, saturationmatrix, int32(pisor), nil, nil, vimage_flags(kvimagenoflags))
                    effectimagebuffersareswapped = true
                } else {
                    vimagematrixmultiply_argb8888(&effectinbuffer, &effectoutbuffer, saturationmatrix, int32(pisor), nil, nil, vimage_flags(kvimagenoflags))
                }
            }

            if !effectimagebuffersareswapped {
                effectimage = uigraphicsgetimagefromcurrentimagecontext()!
            }

            uigraphicsendimagecontext()

            if effectimagebuffersareswapped {
                effectimage = uigraphicsgetimagefromcurrentimagecontext()!
            }

            uigraphicsendimagecontext()
        }

        // set up output context.
        uigraphicsbeginimagecontextwithoptions(size, false, uiscreen.main.scale)
        let outputcontext = uigraphicsgetcurrentcontext()
        outputcontext?.scaleby(x: 1.0, y: -1.0)
        outputcontext?.translateby(x: 0, y: -size.height)

        // draw base image.
        outputcontext?.draw(self.cgimage!, in: imagerect)

        // draw effect image.
        if hasblur {
            outputcontext?.savegstate()
            if let image = maskimage {
                outputcontext?.clip(to: imagerect, mask: image.cgimage!);
            }
            outputcontext?.draw(effectimage.cgimage!, in: imagerect)
            outputcontext?.restoregstate()
        }

        // add in color tint.
        if let color = tintcolor {
            outputcontext?.savegstate()
            outputcontext?.setfillcolor(color.cgcolor)
            outputcontext?.fill(imagerect)
            outputcontext?.restoregstate()
        }

        // output image is ready.
        let outputimage = uigraphicsgetimagefromcurrentimagecontext()
        uigraphicsendimagecontext()

        return outputimage

    }


    // mark: image from url

    /**
     creates a new image from a url with optional caching. if cached, the cached image is returned. otherwise, a place holder is used until the image from web is returned by the closure.

     - parameter url: the image url.
     - parameter placeholder: the placeholder image.
     - parameter shouldcacheimage: weather or not we should cache the nsurl response (default: true)
     - parameter closure: returns the image from the web the first time is fetched.

     - returns a new image
     */
    class func image(fromurl url: string, placeholder: uiimage, shouldcacheimage: bool = true, closure: @escaping (_ image: uiimage?) -> ()) -> uiimage? {
        // from cache
        if shouldcacheimage {
            if let image = uiimage.shared.object(forkey: url as anyobject) as? uiimage {
                closure(nil)
                return image
            }
        }
        // fetch image
        let session = urlsession(configuration: urlsessionconfiguration.default)
        if let nsurl = url(string: url) {
            session.datatask(with: nsurl, completionhandler: { (data, response, error) -> void in
                if (error != nil) {
                    dispatchqueue.main.async {
                        closure(nil)
                    }
                }
                if let data = data, let image = uiimage(data: data) {
                    if shouldcacheimage {
                        uiimage.shared.setobject(image, forkey: url as anyobject)
                    }
                    dispatchqueue.main.async {
                        closure(image)
                    }
                }
                session.finishtasksandinvalidate()
            }).resume()
        }
        return placeholder
    }
}

自定义创建轮播组件(第二步,扩展uiimageview)

import foundation
import uikit
import quartzcore

public extension uiimageview {

    /**
     loads an image from a url. if cached, the cached image is returned. otherwise, a place holder is used until the image from web is returned by the closure.

     - parameter url: the image url.
     - parameter placeholder: the placeholder image.
     - parameter fadein: weather the mage should fade in.
     - parameter closure: returns the image from the web the first time is fetched.

     - returns a new image
     */
    func imagefromurl(_ url: string, placeholder: uiimage, fadein: bool = true, shouldcacheimage: bool = true, closure: ((_ image: uiimage?) -> ())? = nil)
    {
        self.image = uiimage.image(fromurl: url, placeholder: placeholder, shouldcacheimage: shouldcacheimage) {
            (image: uiimage?) in
            if image == nil {
                return
            }
            self.image = image
            if fadein {
                let transition = catransition()
                transition.duration = 0.5
                transition.timingfunction = camediatimingfunction(name: kcamediatimingfunctioneaseineaseout)
                transition.type = kcatransitionfade
                self.layer.add(transition, forkey: nil)
            }
            closure?(image)
        }
    }
}

自定义轮播组件(第三步,定义轮播组件控制器)

//
//  slidergallerycontroller.swift
//  hangge_1314
//
//  created by hangge on 2018/2/5.
//  图片轮播的controller
//

import uikit

//定义图片轮播组件的接口
protocol slidergallerycontrollerdelegate{
    //获取数据源
    func gallerydatasource()->[string]
    //获取内部scrollerview的宽高尺寸
    func galleryscrollerviewsize()->cgsize
}

//图片轮播组件控制器
class slidergallerycontroller: uiviewcontroller,uiscrollviewdelegate{
    //接口对象
    var delegate : slidergallerycontrollerdelegate!

    //屏幕宽度
    let kscreenwidth = uiscreen.main.bounds.size.width

    //当前展示的图片索引
    var currentindex : int = 0

    //数据源
    var datasource : [string]?

    //用于轮播的左中右三个image(不管几张图片都是这三个imageview交替使用)
    var leftimageview , middleimageview , rightimageview : uiimageview?

    //放置imageview的滚动视图
    var scrollerview : uiscrollview?

    //scrollview的宽和高
    var scrollerviewwidth : cgfloat?
    var scrollerviewheight : cgfloat?

    //页控制器(小圆点)
    var pagecontrol : uipagecontrol?

    //加载指示符(用来当iamgeview还没将图片显示出来时,显示的图片)
    var placeholderimage:uiimage!

    //自动滚动计时器
    var autoscrolltimer:timer?

    override func viewdidload() {
        super.viewdidload()

        //获取并设置scrollerview尺寸
        let size : cgsize = self.delegate.galleryscrollerviewsize()
        self.scrollerviewwidth = size.width
        self.scrollerviewheight = size.height

        //获取数据
        self.datasource =  self.delegate.gallerydatasource()
        //设置scrollerview
        self.configurescrollerview()
        //设置加载指示图片
        self.configureplaceholder()
        //设置imageview
        self.configureimageview()
        //设置页控制器
        self.configurepagecontroller()
        //设置自动滚动计时器
        self.configureautoscrolltimer()

        self.view.backgroundcolor = uicolor.black
    }

    //设置scrollerview
    func configurescrollerview(){
        self.scrollerview = uiscrollview(frame: cgrect(x: 0,y: 0,
                                    width: self.scrollerviewwidth!,
                                    height: self.scrollerviewheight!))
        self.scrollerview?.backgroundcolor = uicolor.red
        self.scrollerview?.delegate = self
        self.scrollerview?.contentsize = cgsize(width: self.scrollerviewwidth! * 3,
                                                height: self.scrollerviewheight!)
        //滚动视图内容区域向左偏移一个view的宽度
        self.scrollerview?.contentoffset = cgpoint(x: self.scrollerviewwidth!, y: 0)
        self.scrollerview?.ispagingenabled = true
        self.scrollerview?.bounces = false
        self.view.addsubview(self.scrollerview!)

    }

    //设置加载指示图片(图片还未加载出来时显示的)
    func configureplaceholder(){
        //这里我使用imagehelper将文字转换成图片,作为加载指示符
        let font = uifont.systemfont(ofsize: 17.0, weight: uifont.weight.medium)
        let size = cgsize(width: self.scrollerviewwidth!, height: self.scrollerviewheight!)
        placeholderimage = uiimage(text: "图片加载中...", font:font,
                                   color:uicolor.white, size:size)!
    }

    //设置imageview
    func configureimageview(){
        self.leftimageview = uiimageview(frame: cgrect(x: 0, y: 0,
                                                       width: self.scrollerviewwidth!,
                                                       height: self.scrollerviewheight!))
        self.middleimageview = uiimageview(frame: cgrect(x: self.scrollerviewwidth!, y: 0,
                                                         width: self.scrollerviewwidth!,
                                                         height: self.scrollerviewheight! ))
        self.rightimageview = uiimageview(frame: cgrect(x: 2*self.scrollerviewwidth!, y: 0,
                                                        width: self.scrollerviewwidth!,
                                                        height: self.scrollerviewheight!))
        self.scrollerview?.showshorizontalscrollindicator = false

        //设置初始时左中右三个imageview的图片(分别时数据源中最后一张,第一张,第二张图片)
        if(self.datasource?.count != 0){
            resetimageviewsource()
        }

        self.scrollerview?.addsubview(self.leftimageview!)
        self.scrollerview?.addsubview(self.middleimageview!)
        self.scrollerview?.addsubview(self.rightimageview!)
    }

    //设置页控制器
    func configurepagecontroller() {
        self.pagecontrol = uipagecontrol(frame: cgrect(x: kscreenwidth/2-60,
                        y: self.scrollerviewheight! - 20, width: 120, height: 20))
        self.pagecontrol?.numberofpages = (self.datasource?.count)!
        self.pagecontrol?.isuserinteractionenabled = false
        self.view.addsubview(self.pagecontrol!)
    }

    //设置自动滚动计时器
    func configureautoscrolltimer() {
        //设置一个定时器,每三秒钟滚动一次
        autoscrolltimer = timer.scheduledtimer(timeinterval: 3, target: self,
                selector: #selector(slidergallerycontroller.letitscroll),
                userinfo: nil, repeats: true)
    }

    //计时器时间一到,滚动一张图片
    @objc func letitscroll(){
        let offset = cgpoint(x: 2*scrollerviewwidth!, y: 0)
        self.scrollerview?.setcontentoffset(offset, animated: true)
    }

    //每当滚动后重新设置各个imageview的图片
    func resetimageviewsource() {
        //当前显示的是第一张图片
        if self.currentindex == 0 {
            self.leftimageview?.imagefromurl(self.datasource!.last!,
                                             placeholder: placeholderimage)
            self.middleimageview?.imagefromurl(self.datasource!.first!,
                                               placeholder: placeholderimage)
            let rightimageindex = (self.datasource?.count)!>1 ? 1 : 0 //保护
            self.rightimageview?.imagefromurl(self.datasource![rightimageindex],
                                              placeholder: placeholderimage)
        }
            //当前显示的是最好一张图片
        else if self.currentindex == (self.datasource?.count)! - 1 {
            self.leftimageview?.imagefromurl(self.datasource![self.currentindex-1],
                                             placeholder: placeholderimage)
            self.middleimageview?.imagefromurl(self.datasource!.last!,
                                               placeholder: placeholderimage)
            self.rightimageview?.imagefromurl(self.datasource!.first!,
                                              placeholder: placeholderimage)
        }
            //其他情况
        else{
            self.leftimageview?.imagefromurl(self.datasource![self.currentindex-1],
                                             placeholder: placeholderimage)
            self.middleimageview?.imagefromurl(self.datasource![self.currentindex],
                                               placeholder: placeholderimage)
            self.rightimageview?.imagefromurl(self.datasource![self.currentindex+1],
                                              placeholder: placeholderimage)
        }
    }

    //scrollview滚动完毕后触发
    func scrollviewdidscroll(_ scrollview: uiscrollview) {
        //获取当前偏移量
        let offset = scrollview.contentoffset.x

        if(self.datasource?.count != 0){

            //如果向左滑动(显示下一张)
            if(offset >= self.scrollerviewwidth!*2){
                //还原偏移量
                scrollview.contentoffset = cgpoint(x: self.scrollerviewwidth!, y: 0)
                //视图索引+1
                self.currentindex = self.currentindex + 1

                if self.currentindex == self.datasource?.count {
                    self.currentindex = 0
                }
            }

            //如果向右滑动(显示上一张)
            if(offset <= 0){
                //还原偏移量
                scrollview.contentoffset = cgpoint(x: self.scrollerviewwidth!, y: 0)
                //视图索引-1
                self.currentindex = self.currentindex - 1

                if self.currentindex == -1 {
                    self.currentindex = (self.datasource?.count)! - 1
                }
            }

            //重新设置各个imageview的图片
            resetimageviewsource()
            //设置页控制器当前页码
            self.pagecontrol?.currentpage = self.currentindex
        }
    }

    //手动拖拽滚动开始
    func scrollviewwillbegindragging(_ scrollview: uiscrollview) {
        //使自动滚动计时器失效(防止用户手动移动图片的时候这边也在自动滚动)
        autoscrolltimer?.invalidate()
    }

    //手动拖拽滚动结束
    func scrollviewdidenddragging(_ scrollview: uiscrollview,
                                  willdecelerate decelerate: bool) {
        //重新启动自动滚动计时器
        configureautoscrolltimer()
    }

    //重新加载数据
    func reloaddata() {
        //索引重置
        self.currentindex = 0
        //重新获取数据
        self.datasource =  self.delegate.gallerydatasource()
        //页控制器更新
        self.pagecontrol?.numberofpages = (self.datasource?.count)!
        self.pagecontrol?.currentpage = 0
        //重新设置各个imageview的图片
        resetimageviewsource()
    }

    override func didreceivememorywarning() {
        super.didreceivememorywarning()
    }
}

第四步(开始使用)

//
//  bannerviewcontroller.swift
//  iostest
//
//  created by 陕西帮你电子科技有限公司 on 2018/5/4.
//  copyright ? 2018年 陕西帮你电子科技有限公司. all rights reserved.
//  实现图片轮播
//

import uikit
import swiftyjson
import alamofire
//实现slidergallerycontrollerdelegate接口
class bannerviewcontroller: uiviewcontroller,slidergallerycontrollerdelegate {

    //获取屏幕的宽度
    let screenwidth = uiscreen.main.bounds.size.width
    //自定义的图片轮播的组件
    var slidergallery : slidergallerycontroller!
    //图片轮播的数据源(string类型的数组)
    var imgagedata = [string]()

    override func viewdidload() {
        super.viewdidload()
        //请求服务获取轮播图片
        getimagedata()
    }
    //图片轮播组件接口获取数据源的方法
    func gallerydatasource() -> [string] {
        return imgagedata
    }
    //图片轮播组件接口的方法,获取内部scrollview的尺寸
    func galleryscrollerviewsize() -> cgsize {
        return cgsize(width: screenwidth-20, height: (screenwidth-20)/4*3)
    }
    //点击事件响应
    @objc func handletapaction(_ tap:uitapgesturerecognizer) -> void {
        //获取图片的索引值
        let index = slidergallery.currentindex
        print("宝宝你点击了\(index)张图片")
    }

    //初始化轮播组件
    func initslidergallery(){
        //初始化图片轮播组件
        slidergallery = slidergallerycontroller()
        //设置 slidergallerycontrollerdelegate 接口的监听事件
        slidergallery.delegate = self
        slidergallery.view.frame = cgrect(x: 10, y: 40, width: screenwidth-20, height: (screenwidth-20)/4*3)
        //将图片轮播组件添加到当前视图
        self.addchildviewcontroller(slidergallery)
        self.view.addsubview(slidergallery.view)

        //添加组件的点击事件
        let tap = uitapgesturerecognizer(target: self, action: #selector(bannerviewcontroller.handletapaction(_:)))
        slidergallery.view.addgesturerecognizer(tap)
    }
    //请求服务器获取轮播图片的数据
    func getimagedata(){
      //获取当前时间
      let now = date()
      //当前时间的时间戳
      let timeinterval:timeinterval = now.timeintervalsince1970
      let timestamp = string(timeinterval)
      let url = url(string: "https://47.92.107.28:8000/static/banner.f?_=\(timestamp)")!
        alamofire.request(url,method: .get,parameters: nil,encoding: urlencoding.default,headers:nil).responsejson { response
            in
            switch response.result.issuccess {
            case true:
                if let value = response.result.value{
                    self.imgagedata = []
                    //获取返回的值,转为json对象
                    let img_json = json(value)
                    //json转字符串
                    let json_str = img_json.rawstring()
                    let zhu_url = "https://47.92.107.28:8000"
                    //遍历json数据
                    for(key,item) in img_json["imgs"] {
                        //print("src的值:\(item["src"])")
                        //如果取得的 src 的值为 string类型的话就添加到数组中
                        if let img_url = item["src"].string{
                            //将图片路径添加到数组中
                            self.imgagedata.append(zhu_url+img_url)
                        }
                    }
                    let str = self.imgagedata.joined()
                    //print("请求到返回的数据\(json_str)")
                    //初始化轮播组件
                    self.initslidergallery()
                }
            case false:
                print(response.result.error)
                uialertcontroller.showalert(message: "网络连接失败")
            }
        }
    }
    override func didreceivememorywarning() {
        super.didreceivememorywarning()
        // dispose of any resources that can be recreated.
    }
}