Giter Club home page Giter Club logo

amtaglistview's Introduction

Build Status CocoaPods Coverage Status Carthage compatible Donate

UIScrollView subclass that allows to add a list of highly customizable tags. You can customize colors, border radius, and the tail of the tag. Tags can be added in bulk or dynamically one by one. The newly inserted tag will automatically arrange itself inside the scrollview.

Screenshot

AMTagListView

Setup with CocoaPods

Swift

pod 'AMTagListView'

When using a bridging header:

#import <AMTagListView.h>

When using dynamic frameworks:

@import AMTagListView

Usage

You can create a AMTagListView in your storyboard, or programmatically:

Objective-C

// Init
AMTagListView *tagListView = [[AMTagListView alloc] initWithFrame:frame];
[self.view addSubview:tagListView];

Swift

let tagListView = AMTagListView(frame: frame)
view.addSubview(tagListView)

Adding tags

Objective-C

// Add one tag
[self.tagListView addTag:@"my tag"];

// Add multiple tags
[self.tagListView addTags:@[@"my tag", @"some tag"]];

Swift

// Add one tag
tagListView.addTag("my tag")

// Add multiple tags
tagListView.addTags(["my tag", "some tag"])

Arranging tags

The tags are rearranged when you use the method calls listed above. You can also avoid the auto-rearrange by using the andRearrange: versions of such methods. This is useful when adding a big batch of tags. When you do so you must force the rearrange action manually:

[self.tagListView rearrangeTags];

You can also align the tags to the left or right by setting the tagAlignment property and calling rearrangeTags.

Appearance

Use the AMTagView's UIAppearance selectors to customize its appearance:

Objective-C

[[AMTagView appearance] setRadius:10];

Swift

AMTagView.appearance().radius = 10

Add a payload to a tag

You can add a payload to a single tag by using addTag:withUserInfo::

[self.tagListView addTag:@"hello" withUserInfo:@{ @"data": somePayload }];

Scroll direction

You can control the scroll direction with the scrollDirection property:

[self.tagListView setScrollDirection:AMScrollDirectionHorizontal];

Appearance properties

These are the properties that can be modified:

// Tag's corner radius
[[AMTagView appearance] setRadius:float]

// Tail's length
[[AMTagView appearance] setTagLength:float]

// Inner padding of the tag label
[[AMTagView appearance] setInnerTagPadding:float]

// Radius of the hole punched in the tail
[[AMTagView appearance] setHoleRadius:float]

// Text padding (x for horizontal padding, y for vertical)
[[AMTagView appearance] setTextPadding:CGPoint]

// Text font
[[AMTagView appearance] setTextFont:UIFont]

// The text color
[[AMTagView appearance] setTextColor:UIColor]

// Tag main color
[[AMTagView appearance] setTagColor:UIColor]

// Tag label background color
[[AMTagView appearance] setInnerTagColor:UIColor]

Delegate

This method asks his delegate if a given tag can be added. The method also shows the resulting content size.

- (BOOL)tagList:(AMTagListView *)tagListView shouldAddTagWithText:(NSString *)text resultingContentSize:(CGSize)size;

This method asks his delegate if a given batch of tags can be added. The method also shows the resulting content size.

- (BOOL)tagList:(AMTagListView *)tagListView shouldAddTagsWithText:(NSArray *)text resultingContentSize:(CGSize)size;

This is called when a tag is removed:

- (void)tagList:(AMTagListView *)tagListView didRemoveTag:(UIView<AMTag> *)tag;

Test

To run the test suite install xcpretty gem, launch pod install inside the Tests folder, and run the rake task in the root.

Author

Andrea Mazzini. I'm available for freelance work, feel free to contact me.

Want to support the development of these free libraries? Buy me a coffee ☕️ via Paypal.

Contributors

Thanks to Orta Therox and everyone kind enough to submit a pull request.

MIT License

Copyright (c) 2017 Andrea Mazzini. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

amtaglistview's People

Contributors

andreabusi avatar andreamazz avatar baytelman avatar ealeksandrov avatar orta avatar rafaelmaroxa avatar readmecritic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

amtaglistview's Issues

Limit tags

Hi @andreamazz

First congrats for the project and thanks for sharing.

I started to try this code and would like to know how to limit the number o tags in the tag list view ? For example for only 4 tags. In the current project the view generates a scroll view and so tags keep filling the view. In My case I would like to limit the number of tags to two "lines" of tags at maximum. So the tag list view wouldn't need a scroll view.

Would this change too much your current code ? Could you describe briefly how to implement that using the current code ?

Thanx again and cheers!

iOS6 compatibility

I just have implemented your awesome lib into our project. However, it's supporting only iOS7. Can you please add the support of iOS6 as well. Thank you very much. Looking forward your response.

Tests: Unit test

Things I'd like if you're adding tests for this project during Cocoapod's Test Jam

Tooling: Specta/Expecta

Areas to look at:

  • Improve coverage
  • Add coveralls.io

rearrangeTags in layoutSubviews

the rearrangeTags inside the layoutSubviews causes the scrollview to lag when it tries to go to the last row.
plus while scrolling it calls continuously the rearrangeTags.
if you remove the rearrangeTags it works as it should

Connect it to Parse.com

Hi @andreamazz

I tried without success to link this project to Parse backend.
In one view I would like to add the tags and save them to Parse with a save button and in another view, load them from Parse.

Any suggestion ?

Issue on Rotation : rearrangeTags?

I have an AMTagListView configured with auto layout in a storyboard. The AMTagListView resizes properly on device rotation, but the array of AMTagViews contained therein do not rearrange to expand from portrait to horizontal.

I am assuming that rearrangeTags would be the first place to poke around. Is this correct?
Any help you could provide would be greatly appreciated.

Thanks in advance

parse issue in AMTagView.h

Thanks for the great work. I just met a problem when I add this library to my project. There will be parse error like "unknown type name 'NSString'", I have no idea why this happen. Any suggestion?

Typo in README

Instead of tagListView.addTags:(["my tag", "some tag"]) it should be tagListView.addTags(["my tag", "some tag"]).

AMTagListView's height

A wished request.

Is it possible to estimate the height of an AMTagListView if needed to show all tags which could be increased/decreased dynamically?

AMTagListView removeTag problem

Hi,
I was trying to use two AMTagListView, for example ,AMTagListView1 and AMTagListView2,

when I click one AMTagListView1 , removeTag on AMTagListView1, and add this tag to AMTagListView2, but it's not working properly, can you have a check with this issue?

Thanks

change tagcolor

Hello and thanks for the open source lib.
I have one question regarding the tagColor property.
Is there a way to change it in real time?
i mean i have set it up using:

[[AMTagView appearance] setTagColor:...];

but when i change the theme of my app i would like for it to change along with all other components. Can i do that without recreating the whole object?

thanks

Request Feature

Would be nice if there was on touch up listener with a delegate call back

Button "Add tag" into AMTagListView

Many times me and our team open form where we using AMTagViewList with textfield. And always when we need input new tag we tap to AMTagViewList (this happening automaitcally, by instinct), not to textfield upper. Maybe we add button to add tag in AMTagListView ?

Is there a way to detect when user removed a tag?

I'm trying to notify some app class when a tag was deleted by user. I didn't find any event triggered when this happens so don't see you can detect it.

I could do the change and create a pull request in case it's not implemented and you think it could help other people.

Thanks

Enhancement: Changing textColor on the fly.

Hey!

I have list of my tags. Every tag has 2 states: selected and deselected. I'm tracking selection of my tags in separate NSMutableArray. Of course when those 2 states have different colors (reversed). I noticed that I had send setNeedsLayout message to AMTagView object to redisplay textColor properly:

    self.selectedTags = [NSMutableArray array];

    [self.tagListView addTags:@[@"my tag", @"some tag"]];
    [self.tagListView setTapHandler:^(AMTagView *view) {

        BOOL contains = [self.selectedTags containsObject:[view tagText]];
        contains ? [self.selectedTags removeObject:[view tagText]] : [self.selectedTags addObject:[view tagText]];  // is there better way to track selected tags?

        if (contains) {
            [view setInnerTagColor:[UIColor whiteColor]];
            [view setTextColor:[UIColor redColor]];
        } else {
            [view setInnerTagColor:[UIColor redColor]];
            [view setTextColor:[UIColor whiteColor]];
        }
        [view setNeedsLayout]; // <-- here have to do it manually
    }];

My question is: Maybe it could be worth to override setTextColor method in AMTagView?

- (void)setTextColor:(UIColor *)textColor {
    _textColor = textColor;
    [self setNeedsLayout];
}

[__NSArrayM insertObject:atIndex:]: object cannot be nil

Hi !
I have an issue in rearrangeTags on this line : [self addSubview:obj];

Sometimes I got this exception :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

But when I do this to debug :

if (obj != nil) {
            NSLog(@"add %@", obj.tagText);
            [self addSubview:obj];
        }

the NSLog print the good tagText and I got the same error so I don't understand...
Thanks for your help !

Custom tag view

Developer should be able to use custom tag view, built from scratch, without subclassing AMTagView. This feature could bring much more flexibility to the library.

Demo App: Tags aren't appearing in TagListView.

Hi, slick control!

I used pod try AMTagListView and chose option 2. I built using Xcode 6.1.1 (6A2008a), and ran using an iPhone 5s (8.1) simulator.

When hitting enter, the UITextField does empty, and the tag is created, but it never appears on screen.
After peeking under the hood I found this offending line of code:
screen shot 2015-01-19 at 13 50 44

Is there a reason for this line? After removing it things work properly, but I feel shady just removing lines of code without fully understanding the entire project.

Awesome control btw, thanks for sharing it! :D

Swift 2 / iOS 9 support?

Hello,
when it is expected to have support for iOS 9 / xcode 7 and Swift 2?
Thanks for the great library!

Swift example?

would you mind to provide a simple Swift example. I keep running into all kind of issues trying to add the control (likely because I'm a noob). Thx in advance.

Custom cell not selected

hi
i used Tags insde view inside table cell, but i can't select cell from table to get details (push to another view). and if i tap on cell (outSide of tagsView) work fine.

How can I increase the height of each tag view?

I would like to increase the height of each tag in the taglistview..

one way would be to increase the font size, but I would like to keep the font size at 12points but have the height be 30points.. any idea?

allow user to attach client data to tags

In order to identify the tags in the tapHandler callback, it's sometimes necessary for some meta-information that we don't want to display. It would be nice to be able to attach a black-box object to the tag that can be accessed in the tap handler.

Height before creating the view

#3 This issue's solution tells that you can get the content size after you've created the tag list view, but I have a situation where I need it before. Can you please write a method which calculates that? I tried to look into your files, but there are a couple of interesting lines over there.

Setting text with setupText or setTagText (after adding the tag to tag list) changes the size of the tag

Lets say I have a below setup:

  • An AMTagListView named as tagListView.
  • An AMTagView named as tag1. The text for the tag is "Custom" and it has an accessory image. Below is the code for tag creation and adding it to tagListView:
AMTagView *tag1 = [[AMTagView alloc] initWithFrame:CGRectZero];
[tag1 setAccessoryImage:[UIImage imageNamed:@"close"]];
[tag1 setupWithText:@"Custom"];
[self.tagListView addTagView:tag1];

So when the tag list view shows up on screen, the frame of the tag1: {{10, 39}, {82, 29}}

I wrote a tap handler which does nothing but just resets the text to same text. Code below:

[self.tagListView setTapHandler:^(AMTagView *view) {
     [view setTagText:[NSString stringWithFormat:@"%@", view.tagText]];
}];

If I check the frame after setTagText, it shows up as {{211, 0}, {106, 30}}

This happens because when we use addTagView to add tag to the tagListView, the addTagView method recalculates the width of the tag as shown below:

- (UIView<AMTag> *)addTagView:(UIView<AMTag> *)tagView andRearrange:(BOOL)rearrange {
    if ([tagView isKindOfClass:[AMTagView class]]) {
        UIFont *font = [[[tagView class] appearance] textFont];
        CGSize size = [((AMTagView *)tagView).tagText sizeWithAttributes:@{NSFontAttributeName: font}];
        CGPoint padding = [[[tagView class] appearance] textPadding];
        float tagLength = [[[tagView class] appearance] tagLength];
        size.width = (int)size.width + padding.x * 2 + tagLength;
        size.height = (int)size.height + padding.y;
        size.width = MIN(size.width, self.frame.size.width - self.marginX * 2);
        tagView.frame = (CGRect){{0, 0}, {size.width, size.height}};`
    }
[self.tags addObject:tagView];

We use setupText: or setTagText: to modify the text for the tag that has already been added. Since the tag has already been added, we don't use addTagView: method and hence the above calculation doesn't happen.

As a workaround, I am adding and removing the tag after modifying the text so that it maintains the same padding.

Is this the expected behavior?

Request Feature

It would be great if there was a way to show tags in horizontal direction with number of rows.

There's a retain cycle problem that causes memory leaks in AMTagListView

Brief intro

My app uses your control on each view controller in UIPageViewController. Recently, I detected that there’s a memory leak when scrolling in PageViewController.

I’ve used CRChecker to detect possible retain cycles and troublesome controls, and the analysis indeed shows that your control definitely has this problem.

Possible sources

After brief source inspection I detected few possible sources:

  • - [AMTagListView setup] contains this code:

    self.orientationNotification = [center addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        [self rearrangeTags];
    }];
        self.tagNotification = [center addObserverForName:AMTagViewNotification object:nil queue:nil usingBlock:^(NSNotification *notification) {
        if (self == notification.userInfo[@"superview"]) {
            if (_tapHandler) {
                self.tapHandler(notification.object);
            }
        }
    }];
    
  • - [AMTagListView rearrangeTags] contains this one:

    [self.tags enumerateObjectsUsingBlock:^(AMTagView* obj, NSUInteger idx, BOOL *stop) {
    size = obj.frame.size;
    [self.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[AMTagView class]]) {
            maxY = MAX(maxY, obj.frame.origin.y);
        }
    }];
    
    [self.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[AMTagView class]]) {
            if (obj.frame.origin.y == maxY) {
                maxX = MAX(maxX, obj.frame.origin.x + obj.frame.size.width);
            }
        }
    }];
    
    // Go to a new line if the tag won't fit
    if (size.width + maxX > (self.frame.size.width - self.marginX)) {
        maxY += size.height + self.marginY;
        maxX = 0;
    }
    obj.frame = (CGRect){maxX + self.marginX, maxY, size.width, size.height};
        [self addSubview:obj];
    }];
    

There is link to self in both - [NSNotificationCenter addObserverForName:object:queue:usingBlock] and [NSArray enumerateObjectsUsingBlock:].
And blocks always retain all captured variables.

So now we have a strong reference to AMTagListView that keeps that object in memory until the block object is deallocated.

Possible solution

You should pass weak pointers to self, instead of strong ones.

But …

I’m not sure that the problem is limited to these two cases, so you should check your code further for any other possible sources of memory leaks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.