How do I display the standard checkmark on a UICollectionViewCell?

后端 未结 4 1006
甜味超标
甜味超标 2020-12-02 09:47

I\'m designing an iOS app with a UICollectionView, and I\'d like users to be able to select multiple items within this view. It seems there\'s a standard style of checkmark

相关标签:
4条回答
  • 2020-12-02 10:29

    I ended up recreating the checkmarks using PaintCode. Here's what they look like:

    Custom-made checkmarks

    They're drawn with vector graphics, so they'll look great at whatever size you want. These are 30x30. I also included an option to use a grayed-out checkmark instead of the open circle when an item is not selected.

    To use these, copy the following class into your project. Then, add a UIView to your storyboard or xib, and set its custom class to SSCheckMark.

    SSCheckMark.h

    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM( NSUInteger, SSCheckMarkStyle )
    {
        SSCheckMarkStyleOpenCircle,
        SSCheckMarkStyleGrayedOut
    };
    
    @interface SSCheckMark : UIView
    
    @property (readwrite) bool checked;
    @property (readwrite) SSCheckMarkStyle checkMarkStyle;
    
    @end
    

    SSCheckMark.m

    #import "SSCheckMark.h"
    
    @implementation SSCheckMark
    
    - (void) drawRect:(CGRect)rect
    {
        [super drawRect:rect];
    
        if ( self.checked )
            [self drawRectChecked:rect];
        else
        {
            if ( self.checkMarkStyle == SSCheckMarkStyleOpenCircle )
                [self drawRectOpenCircle:rect];
            else if ( self.checkMarkStyle == SSCheckMarkStyleGrayedOut )
                [self drawRectGrayedOut:rect];
        }
    }
    
    - (void) setChecked:(bool)checked
    {
        _checked = checked;
        [self setNeedsDisplay];
    }
    
    - (void) setCheckMarkStyle:(SSCheckMarkStyle)checkMarkStyle
    {
        _checkMarkStyle = checkMarkStyle;
        [self setNeedsDisplay];
    }
    
    - (void) drawRectChecked: (CGRect) rect
    {
        //// General Declarations
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        //// Color Declarations
        UIColor* checkmarkBlue2 = [UIColor colorWithRed: 0.078 green: 0.435 blue: 0.875 alpha: 1];
    
        //// Shadow Declarations
        UIColor* shadow2 = [UIColor blackColor];
        CGSize shadow2Offset = CGSizeMake(0.1, -0.1);
        CGFloat shadow2BlurRadius = 2.5;
    
        //// Frames
        CGRect frame = self.bounds;
    
        //// Subframes
        CGRect group = CGRectMake(CGRectGetMinX(frame) + 3, CGRectGetMinY(frame) + 3, CGRectGetWidth(frame) - 6, CGRectGetHeight(frame) - 6);
    
    
        //// Group
        {
            //// CheckedOval Drawing
            UIBezierPath* checkedOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(group) + floor(CGRectGetWidth(group) * 0.00000 + 0.5), CGRectGetMinY(group) + floor(CGRectGetHeight(group) * 0.00000 + 0.5), floor(CGRectGetWidth(group) * 1.00000 + 0.5) - floor(CGRectGetWidth(group) * 0.00000 + 0.5), floor(CGRectGetHeight(group) * 1.00000 + 0.5) - floor(CGRectGetHeight(group) * 0.00000 + 0.5))];
            CGContextSaveGState(context);
            CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            [checkmarkBlue2 setFill];
            [checkedOvalPath fill];
            CGContextRestoreGState(context);
    
            [[UIColor whiteColor] setStroke];
            checkedOvalPath.lineWidth = 1;
            [checkedOvalPath stroke];
    
    
            //// Bezier Drawing
            UIBezierPath* bezierPath = [UIBezierPath bezierPath];
            [bezierPath moveToPoint: CGPointMake(CGRectGetMinX(group) + 0.27083 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.54167 * CGRectGetHeight(group))];
            [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group) + 0.41667 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.68750 * CGRectGetHeight(group))];
            [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group) + 0.75000 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.35417 * CGRectGetHeight(group))];
            bezierPath.lineCapStyle = kCGLineCapSquare;
    
            [[UIColor whiteColor] setStroke];
            bezierPath.lineWidth = 1.3;
            [bezierPath stroke];
        }
    }
    
    - (void) drawRectGrayedOut: (CGRect) rect
    {
        //// General Declarations
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        //// Color Declarations
        UIColor* grayTranslucent = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.6];
    
        //// Shadow Declarations
        UIColor* shadow2 = [UIColor blackColor];
        CGSize shadow2Offset = CGSizeMake(0.1, -0.1);
        CGFloat shadow2BlurRadius = 2.5;
    
        //// Frames
        CGRect frame = self.bounds;
    
        //// Subframes
        CGRect group = CGRectMake(CGRectGetMinX(frame) + 3, CGRectGetMinY(frame) + 3, CGRectGetWidth(frame) - 6, CGRectGetHeight(frame) - 6);
    
    
        //// Group
        {
            //// UncheckedOval Drawing
            UIBezierPath* uncheckedOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(group) + floor(CGRectGetWidth(group) * 0.00000 + 0.5), CGRectGetMinY(group) + floor(CGRectGetHeight(group) * 0.00000 + 0.5), floor(CGRectGetWidth(group) * 1.00000 + 0.5) - floor(CGRectGetWidth(group) * 0.00000 + 0.5), floor(CGRectGetHeight(group) * 1.00000 + 0.5) - floor(CGRectGetHeight(group) * 0.00000 + 0.5))];
            CGContextSaveGState(context);
            CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            [grayTranslucent setFill];
            [uncheckedOvalPath fill];
            CGContextRestoreGState(context);
    
            [[UIColor whiteColor] setStroke];
            uncheckedOvalPath.lineWidth = 1;
            [uncheckedOvalPath stroke];
    
    
            //// Bezier Drawing
            UIBezierPath* bezierPath = [UIBezierPath bezierPath];
            [bezierPath moveToPoint: CGPointMake(CGRectGetMinX(group) + 0.27083 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.54167 * CGRectGetHeight(group))];
            [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group) + 0.41667 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.68750 * CGRectGetHeight(group))];
            [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group) + 0.75000 * CGRectGetWidth(group), CGRectGetMinY(group) + 0.35417 * CGRectGetHeight(group))];
            bezierPath.lineCapStyle = kCGLineCapSquare;
    
            [[UIColor whiteColor] setStroke];
            bezierPath.lineWidth = 1.3;
            [bezierPath stroke];
        }
    }
    
    - (void) drawRectOpenCircle: (CGRect) rect
    {
        //// General Declarations
        CGContextRef context = UIGraphicsGetCurrentContext();
    
    
        //// Shadow Declarations
        UIColor* shadow = [UIColor blackColor];
        CGSize shadowOffset = CGSizeMake(0.1, -0.1);
        CGFloat shadowBlurRadius = 0.5;
        UIColor* shadow2 = [UIColor blackColor];
        CGSize shadow2Offset = CGSizeMake(0.1, -0.1);
        CGFloat shadow2BlurRadius = 2.5;
    
        //// Frames
        CGRect frame = self.bounds;
    
        //// Subframes
        CGRect group = CGRectMake(CGRectGetMinX(frame) + 3, CGRectGetMinY(frame) + 3, CGRectGetWidth(frame) - 6, CGRectGetHeight(frame) - 6);
    
    
        //// Group
        {
            //// EmptyOval Drawing
            UIBezierPath* emptyOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(group) + floor(CGRectGetWidth(group) * 0.00000 + 0.5), CGRectGetMinY(group) + floor(CGRectGetHeight(group) * 0.00000 + 0.5), floor(CGRectGetWidth(group) * 1.00000 + 0.5) - floor(CGRectGetWidth(group) * 0.00000 + 0.5), floor(CGRectGetHeight(group) * 1.00000 + 0.5) - floor(CGRectGetHeight(group) * 0.00000 + 0.5))];
            CGContextSaveGState(context);
            CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            CGContextRestoreGState(context);
    
            CGContextSaveGState(context);
            CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor);
            [[UIColor whiteColor] setStroke];
            emptyOvalPath.lineWidth = 1;
            [emptyOvalPath stroke];
            CGContextRestoreGState(context);
        }
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-02 10:30

    Swift 3 version of Chris Vasellis' nice solution:

    import UIKit
    
    enum SSCheckMarkStyle : UInt {
        case OpenCircle
        case GrayedOut
    }
    
    class SSCheckMark: UIView {
    
    private var checkedBool: Bool = false
    // choose whether you like open or grayed out non-selected items
    private var checkMarkStyleReal: SSCheckMarkStyle=SSCheckMarkStyle.GrayedOut
    
    var checked: Bool {
        get {
            return self.checkedBool
        }
        set(checked) {
            self.checkedBool = checked
            self.setNeedsDisplay()
        }
    }
    
    var checkMarkStyle: SSCheckMarkStyle {
        get {
            return self.checkMarkStyleReal
        }
        set(checkMarkStyle) {
            self.checkMarkStyleReal = checkMarkStyle
            self.setNeedsDisplay()
        }
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        if self.checked {
            self.drawRectChecked(rect: rect)
        } else {
            if self.checkMarkStyle == SSCheckMarkStyle.OpenCircle {
                self.drawRectOpenCircle(rect: rect)
            } else if self.checkMarkStyle == SSCheckMarkStyle.GrayedOut {
                self.drawRectGrayedOut(rect: rect)
            }
        }
    }
    
    func drawRectChecked(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        let checkmarkBlue2 = UIColor(red: 0.078, green: 0.435, blue: 0.875, alpha: 1)
        let shadow2 = UIColor.black
    
        let shadow2Offset = CGSize(width: 0.1, height: -0.1)
        let shadow2BlurRadius = 2.5
        let frame = self.bounds
        let group = CGRect(x: frame.minX + 3, y: frame.minY + 3, width: frame.width - 6, height: frame.height - 6)
    
        let checkedOvalPath = UIBezierPath(ovalIn: CGRect(x: group.minX + floor(group.width * 0.00000 + 0.5), y: group.minY + floor(group.height * 0.00000 + 0.5), width: floor(group.width * 1.00000 + 0.5) - floor(group.width * 0.00000 + 0.5), height: floor(group.height * 1.00000 + 0.5) - floor(group.height * 0.00000 + 0.5)))
    
        context!.saveGState()
        context!.setShadow(offset: shadow2Offset, blur: CGFloat(shadow2BlurRadius), color: shadow2.cgColor)
        checkmarkBlue2.setFill()
        checkedOvalPath.fill()
        context!.restoreGState()
        UIColor.white.setStroke()
        checkedOvalPath.lineWidth = 1
        checkedOvalPath.stroke()
        let bezierPath = UIBezierPath()
        bezierPath.move(to: CGPoint(x: group.minX + 0.27083 * group.width, y: group.minY + 0.54167 * group.height))
        bezierPath.addLine(to: CGPoint(x: group.minX + 0.41667 * group.width, y: group.minY + 0.68750 * group.height))
        bezierPath.addLine(to: CGPoint(x: group.minX + 0.75000 * group.width, y: group.minY + 0.35417 * group.height))
        bezierPath.lineCapStyle = CGLineCap.square
        UIColor.white.setStroke()
        bezierPath.lineWidth = 1.3
        bezierPath.stroke()
    }
    
    func drawRectGrayedOut(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        let grayTranslucent = UIColor(red: 1, green: 1, blue: 1, alpha: 0.6)
        let shadow2 = UIColor.black
        let shadow2Offset = CGSize(width: 0.1, height: -0.1)
        let shadow2BlurRadius = 2.5
        let frame = self.bounds
        let group = CGRect(x: frame.minX + 3, y: frame.minY + 3, width: frame.width - 6, height: frame.height - 6)
        let uncheckedOvalPath = UIBezierPath(ovalIn: CGRect(x: group.minX + floor(group.width * 0.00000 + 0.5), y: group.minY + floor(group.height * 0.00000 + 0.5), width: floor(group.width * 1.00000 + 0.5) - floor(group.width * 0.00000 + 0.5), height: floor(group.height * 1.00000 + 0.5) - floor(group.height * 0.00000 + 0.5)))
    
        context!.saveGState()
        context!.setShadow(offset: shadow2Offset, blur: CGFloat(shadow2BlurRadius), color: shadow2.cgColor)
        grayTranslucent.setFill()
        uncheckedOvalPath.fill()
        context!.restoreGState()
        UIColor.white.setStroke()
        uncheckedOvalPath.lineWidth = 1
        uncheckedOvalPath.stroke()
        let bezierPath = UIBezierPath()
    
        bezierPath.move(to: CGPoint(x: group.minX + 0.27083 * group.width, y: group.minY + 0.54167 * group.height))
        bezierPath.addLine(to: CGPoint(x: group.minX + 0.41667 * group.width, y: group.minY + 0.68750 * group.height))
        bezierPath.addLine(to: CGPoint(x: group.minX + 0.75000 * group.width, y: group.minY + 0.35417 * group.height))
        bezierPath.lineCapStyle = CGLineCap.square
        UIColor.white.setStroke()
        bezierPath.lineWidth = 1.3
        bezierPath.stroke()
    }
    
    func drawRectOpenCircle(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        let shadow = UIColor.black
        let shadowOffset = CGSize(width: 0.1, height: -0.1)
        let shadowBlurRadius = 0.5
        let shadow2 = UIColor.black
        let shadow2Offset = CGSize(width: 0.1, height: -0.1)
        let shadow2BlurRadius = 2.5
        let frame = self.bounds
        let group = CGRect(x: frame.minX + 3, y: frame.minY + 3, width: frame.width - 6, height: frame.height - 6)
        let emptyOvalPath = UIBezierPath(ovalIn: CGRect(x: group.minX + floor(group.width * 0.00000 + 0.5), y: group.minY + floor(group.height * 0.00000 + 0.5), width: floor(group.width * 1.00000 + 0.5) - floor(group.width * 0.00000 + 0.5), height: floor(group.height * 1.00000 + 0.5) - floor(group.height * 0.00000 + 0.5)))
    
        context!.saveGState()
        context!.setShadow(offset: shadow2Offset, blur: CGFloat(shadow2BlurRadius), color: shadow2.cgColor)
    
        context!.restoreGState()
        context!.saveGState()
        context!.setShadow(offset: shadowOffset, blur: CGFloat(shadowBlurRadius), color: shadow.cgColor)
        UIColor.white.setStroke()
        emptyOvalPath.lineWidth = 1
        emptyOvalPath.stroke()
        context!.restoreGState()
    
    }
    }
    

    To use it in your code, create a file called SSCheckMark.swift with the above contents, and assign it to your View. I use it in CollectionViewCells, for which I have created a custom class (code simplified heavily):

    class myCollectionViewCell: UICollectionViewCell {
    
        var checkmarkView: SSCheckMark!
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            checkmarkView = SSCheckMark(frame: CGRect(x: frame.width-40, y: 10, width: 35, height: 35))
            checkmarkView.backgroundColor = UIColor.white
            myView.addSubview(checkmarkView)
        }
    }
    

    And in my UIViewController, I have this:

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:ProductCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as! myCollectionViewCell
        cell.checkmarkView.checked = myBoolValue
        return cell
    }
    
    0 讨论(0)
  • 2020-12-02 10:33

    C# version of the same code

    public class CheckMarkView : UIView
    {
        private bool _checked;
        private CheckMarkStyle _checkMarkStyle;
    
        public CheckMarkView()
        {
            Opaque = false;
        }
    
        public bool Checked
        {
            get
            {
                return _checked;
            }
            set
            {
                _checked = value;
                SetNeedsDisplay();
            }
        }
    
        public CheckMarkStyle CheckMarkStyle
        {
            get
            {
                return _checkMarkStyle;
            }
            set
            {
                _checkMarkStyle = value;
                SetNeedsDisplay();
            }
        }
    
        public override void Draw(CGRect rect)
        {
            if (Checked)
                DrawRectChecked(rect);
            else if (CheckMarkStyle == CheckMarkStyle.OpenCircle)
                DrawRectOpenCircle(rect);
            else if (CheckMarkStyle == CheckMarkStyle.GrayedOut)
                DrawRectGrayedOut(rect);
        }
    
    
        private void DrawRectChecked(CGRect rect)
        {
            var context = UIGraphics.GetCurrentContext();
    
            var checkmarkBlue2 = UIColor.FromRGBA(0.078f, 0.435f, 0.875f, 1f);
    
            // Shadow Declarations
            var shadow2 = UIColor.Brown;
            var shadow2Offset = new CGSize(0.1, -0.1);
            nfloat shadow2BlurRadius = 2.5f;
    
            var frame = Bounds;
    
            // Subframes
            var group = new CGRect(frame.GetMinX() + 3, frame.GetMinY() + 3, frame.Width - 6, frame.Height - 6);
    
    
            // CheckedOval Drawing
            var checkedOvalPath = UIBezierPath.FromOval(new CGRect(group.GetMinX() + Math.Floor(group.Width * 0.00000 + 0.5), group.GetMinY() + Math.Floor(group.Height * 0.00000 + 0.5), Math.Floor(group.Width * 1.00000 + 0.5) - Math.Floor(group.Width * 0.00000 + 0.5), Math.Floor(group.Height * 1.00000 + 0.5) - Math.Floor(group.Height * 0.00000f + 0.5f)));
            context.SaveState();
            context.SetShadow(shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            checkmarkBlue2.SetFill();
            checkedOvalPath.Fill();
            context.RestoreState();
    
            UIColor.White.SetStroke();
            checkedOvalPath.LineWidth = 1;
            checkedOvalPath.Stroke();
    
    
            // Bezier Drawing
            var bezierPath = new UIBezierPath();
            bezierPath.MoveTo(new CGPoint(group.GetMinX() + 0.27083f * group.Width, group.GetMinY() + 0.54167f * group.Height));
            bezierPath.AddLineTo(new CGPoint(group.GetMinX() + 0.41667f * group.Width, group.GetMinY() + 0.68750f * group.Height));
            bezierPath.AddLineTo(new CGPoint(group.GetMinX() + 0.75000f * group.Width, group.GetMinY() + 0.35417f * group.Height));
            bezierPath.LineCapStyle = CGLineCap.Square;
    
            UIColor.White.SetStroke();
            bezierPath.LineWidth = 1.3f;
            bezierPath.Stroke();
        }
    
        private void DrawRectGrayedOut(CGRect rect)
        {
            var context = UIGraphics.GetCurrentContext();
    
            var grayTranslucent = UIColor.FromRGBA(1, 1, 1, 0.6f);
    
            // Shadow Declarations
            var shadow2 = UIColor.Black;
            var shadow2Offset = new CGSize(0.1, -0.1);
            nfloat shadow2BlurRadius = 2.5f;
    
            var frame = Bounds;
    
            // Subframes
            var group = new CGRect(frame.GetMinX() + 3, frame.GetMinY() + 3, frame.Width - 6, frame.Height - 6);
    
            // UncheckedOval Drawing
            var uncheckedOvalPath = UIBezierPath.FromOval(new CGRect(group.GetMinX() + Math.Floor(group.Width * 0.00000 + 0.5), group.GetMinY() + Math.Floor(group.Height * 0.00000 + 0.5), Math.Floor(group.Width * 1.00000 + 0.5) - Math.Floor(group.Width * 0.00000 + 0.5), Math.Floor(group.Height * 1.00000 + 0.5) - Math.Floor(group.Height * 0.00000 + 0.5)));
            context.SaveState();
            context.SetShadow(shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            grayTranslucent.SetFill();
            uncheckedOvalPath.Fill();
            context.RestoreState();
            UIColor.White.SetStroke();
            uncheckedOvalPath.LineWidth = 1f;
            uncheckedOvalPath.Stroke();
    
    
            // Bezier Drawing
            var bezierPath = new UIBezierPath();
            bezierPath.MoveTo(new CGPoint(group.GetMinX() + 0.27083 * group.Width, group.GetMinY() + 0.54167 * group.Height));
            bezierPath.AddLineTo(new CGPoint(group.GetMinX() + 0.41667 * group.Width, group.GetMinY() + 0.68750 * group.Height));
            bezierPath.AddLineTo(new CGPoint(group.GetMinX() + 0.75000 * group.Width, group.GetMinY() + 0.35417 * group.Height));
            bezierPath.LineCapStyle = CGLineCap.Square;
            UIColor.White.SetStroke();
            bezierPath.LineWidth = 1.3f;
            bezierPath.Stroke();
        }
    
        private void DrawRectOpenCircle(CGRect rect)
        {
            var context = UIGraphics.GetCurrentContext();
    
            // Shadow Declarations
            var shadow = UIColor.Black;
            var shadowOffset = new CGSize(0.1, -0.1);
            nfloat shadowBlurRadius = 0.5f;
            var shadow2 = UIColor.Black;
            var shadow2Offset = new CGSize(0.1, -0.1);
            nfloat shadow2BlurRadius = 2.5f;
    
            var frame = Bounds;
    
            // Subframes
            var group = new CGRect(frame.GetMinX() + 3, frame.GetMinY() + 3, frame.Width - 6, frame.Height - 6);
    
    
            // EmptyOval Drawing
            var emptyOvalPath = UIBezierPath.FromOval(new CGRect(group.GetMinX() + Math.Floor(group.Width * 0.00000 + 0.5), group.GetMinY() + Math.Floor(group.Height * 0.00000 + 0.5), Math.Floor(group.Width * 1.00000 + 0.5) - Math.Floor(group.Width * 0.00000 + 0.5), Math.Floor(group.Height * 1.00000 + 0.5) - Math.Floor(group.Height * 0.00000 + 0.5)));
            context.SaveState();
            context.SetShadow(shadow2Offset, shadow2BlurRadius, shadow2.CGColor);
            context.RestoreState();
            context.SaveState();
            context.SetShadow(shadowOffset, shadowBlurRadius, shadow.CGColor);
            UIColor.White.SetStroke();
            emptyOvalPath.LineWidth = 1;
            emptyOvalPath.Stroke();
            context.RestoreState();
        }
    }
    
    public enum CheckMarkStyle
    {
        OpenCircle,
        GrayedOut
    }
    
    0 讨论(0)
  • 2020-12-02 10:48

    One possibility is creating a UIView that draws concentric circles, then a checkmark character from your font of choice. To find checkmark characters, go to Edit > Special Characters within Xcode (or any other application with that menu item), and search for "check". When you select one of the search results, you'll see font variations at the bottom right.

    enter image description here

    0 讨论(0)
提交回复
热议问题