当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS开发swift 图片轮播功能实现方法

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

2018年09月14日  | 移动技术网移动技术  | 我要评论

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

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.
    }
}

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网