单军华
2016-12-23 5e0025a973fb918f9790fa950d862e713acc807f
右上角加号点击弹出效果demo,附上效果图
72 files added
2908 ■■■■■ changed files
Popover/LICENSE 21 ●●●●● patch | view | raw | blame | history
Popover/Popover.podspec 12 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.pbxproj 340 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.xcworkspace/contents.xcworkspacedata 7 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/lifution.xcuserdatad/UserInterfaceState.xcuserstate patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/steven.xcuserdatad/UserInterfaceState.xcuserstate patch | view | raw | blame | history
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/steven.xcuserdatad/WorkspaceSettings.xcsettings 16 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 87 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/Popover.xcscheme 91 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist 22 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 5 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcschemes/Popover.xcscheme 91 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcschemes/xcschememanagement.plist 22 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 5 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/Popover.xcscheme 91 ●●●●● patch | view | raw | blame | history
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/xcschememanagement.plist 22 ●●●●● patch | view | raw | blame | history
Popover/Popover/AppDelegate.h 17 ●●●●● patch | view | raw | blame | history
Popover/Popover/AppDelegate.m 46 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Contents.json 74 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/Contents.json 6 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_friend.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_friend.imageset/contacts_add_friend@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_money.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_money.imageset/contacts_add_money@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_newmessage.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_newmessage.imageset/contacts_add_newmessage@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_scan.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/contacts_add_scan.imageset/contacts_add_scan@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/navigationItem_menu.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/navigationItem_menu.imageset/navigationItem_menu@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_QR.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_QR.imageset/right_menu_QR@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_addFri.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_addFri.imageset/right_menu_addFri@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_facetoface.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_facetoface.imageset/right_menu_facetoface@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_multichat.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_multichat.imageset/right_menu_multichat@2x.png patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_payMoney.imageset/Contents.json 21 ●●●●● patch | view | raw | blame | history
Popover/Popover/Assets.xcassets/right_menu_payMoney.imageset/right_menu_payMoney@2x.png patch | view | raw | blame | history
Popover/Popover/Base.lproj/LaunchScreen.storyboard 31 ●●●●● patch | view | raw | blame | history
Popover/Popover/Base.lproj/Main.storyboard 190 ●●●●● patch | view | raw | blame | history
Popover/Popover/Info.plist 44 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverAction.h 28 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverAction.m 34 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverView.h 32 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverView.m 398 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverViewCell.h 34 ●●●●● patch | view | raw | blame | history
Popover/Popover/PopoverView/PopoverViewCell.m 109 ●●●●● patch | view | raw | blame | history
Popover/Popover/ViewController.h 15 ●●●●● patch | view | raw | blame | history
Popover/Popover/ViewController.m 112 ●●●●● patch | view | raw | blame | history
Popover/Popover/main.m 16 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverAction.h 27 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverAction.m 34 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverView.h 32 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverView.m 385 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverViewCell.h 34 ●●●●● patch | view | raw | blame | history
Popover/PopoverView/PopoverViewCell.m 106 ●●●●● patch | view | raw | blame | history
Popover/README.md 62 ●●●●● patch | view | raw | blame | history
Popover/效果图.png patch | view | raw | blame | history
Popover/LICENSE
New file
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Popover (https://github.com/lifution)
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.
Popover/Popover.podspec
New file
@@ -0,0 +1,12 @@
Pod::Spec.new do |s|
    s.name = "Popover"
    s.version = "1.0"
    s.summary = "A simple Popover of Menu"
    s.license = { :type => "MIT", :file => "LICENSE" }
    s.homepage = "https://github.com/lifution/Popover"
    s.author = { "Steven" => "https://github.com/lifution" }
    s.source = { :git => "https://github.com/lifution/Popover.git", :tag => "1.0.0" }
    s.requires_arc = true
    s.platform = :ios, "6.0"
    s.source_files = "PopoverView/*", "*.{h,m}"
end
Popover/Popover.xcodeproj/project.pbxproj
New file
@@ -0,0 +1,340 @@
// !$*UTF8*$!
{
    archiveVersion = 1;
    classes = {
    };
    objectVersion = 46;
    objects = {
/* Begin PBXBuildFile section */
        B057A05C1E013E180076287C /* PopoverAction.m in Sources */ = {isa = PBXBuildFile; fileRef = B057A0571E013E180076287C /* PopoverAction.m */; };
        B057A05D1E013E180076287C /* PopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = B057A0591E013E180076287C /* PopoverView.m */; };
        B057A05E1E013E180076287C /* PopoverViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B057A05B1E013E180076287C /* PopoverViewCell.m */; };
        DEF76E691C3B863C00CC7AF9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DEF76E681C3B863C00CC7AF9 /* main.m */; };
        DEF76E6C1C3B863C00CC7AF9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DEF76E6B1C3B863C00CC7AF9 /* AppDelegate.m */; };
        DEF76E6F1C3B863C00CC7AF9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DEF76E6E1C3B863C00CC7AF9 /* ViewController.m */; };
        DEF76E721C3B863C00CC7AF9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DEF76E701C3B863C00CC7AF9 /* Main.storyboard */; };
        DEF76E741C3B863C00CC7AF9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEF76E731C3B863C00CC7AF9 /* Assets.xcassets */; };
        DEF76E771C3B863C00CC7AF9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DEF76E751C3B863C00CC7AF9 /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
        B057A0561E013E180076287C /* PopoverAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverAction.h; sourceTree = "<group>"; };
        B057A0571E013E180076287C /* PopoverAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PopoverAction.m; sourceTree = "<group>"; };
        B057A0581E013E180076287C /* PopoverView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverView.h; sourceTree = "<group>"; };
        B057A0591E013E180076287C /* PopoverView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PopoverView.m; sourceTree = "<group>"; };
        B057A05A1E013E180076287C /* PopoverViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverViewCell.h; sourceTree = "<group>"; };
        B057A05B1E013E180076287C /* PopoverViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PopoverViewCell.m; sourceTree = "<group>"; };
        DEF76E641C3B863C00CC7AF9 /* Popover.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Popover.app; sourceTree = BUILT_PRODUCTS_DIR; };
        DEF76E681C3B863C00CC7AF9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
        DEF76E6A1C3B863C00CC7AF9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
        DEF76E6B1C3B863C00CC7AF9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
        DEF76E6D1C3B863C00CC7AF9 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
        DEF76E6E1C3B863C00CC7AF9 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
        DEF76E711C3B863C00CC7AF9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
        DEF76E731C3B863C00CC7AF9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
        DEF76E761C3B863C00CC7AF9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
        DEF76E781C3B863C00CC7AF9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
        DEF76E611C3B863C00CC7AF9 /* Frameworks */ = {
            isa = PBXFrameworksBuildPhase;
            buildActionMask = 2147483647;
            files = (
            );
            runOnlyForDeploymentPostprocessing = 0;
        };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
        B057A0551E013E180076287C /* PopoverView */ = {
            isa = PBXGroup;
            children = (
                B057A0581E013E180076287C /* PopoverView.h */,
                B057A0591E013E180076287C /* PopoverView.m */,
                B057A05A1E013E180076287C /* PopoverViewCell.h */,
                B057A05B1E013E180076287C /* PopoverViewCell.m */,
                B057A0561E013E180076287C /* PopoverAction.h */,
                B057A0571E013E180076287C /* PopoverAction.m */,
            );
            path = PopoverView;
            sourceTree = "<group>";
        };
        DEF76E5B1C3B863C00CC7AF9 = {
            isa = PBXGroup;
            children = (
                DEF76E661C3B863C00CC7AF9 /* Popover */,
                DEF76E651C3B863C00CC7AF9 /* Products */,
            );
            sourceTree = "<group>";
        };
        DEF76E651C3B863C00CC7AF9 /* Products */ = {
            isa = PBXGroup;
            children = (
                DEF76E641C3B863C00CC7AF9 /* Popover.app */,
            );
            name = Products;
            sourceTree = "<group>";
        };
        DEF76E661C3B863C00CC7AF9 /* Popover */ = {
            isa = PBXGroup;
            children = (
                B057A0551E013E180076287C /* PopoverView */,
                DEF76E6A1C3B863C00CC7AF9 /* AppDelegate.h */,
                DEF76E6B1C3B863C00CC7AF9 /* AppDelegate.m */,
                DEF76E6D1C3B863C00CC7AF9 /* ViewController.h */,
                DEF76E6E1C3B863C00CC7AF9 /* ViewController.m */,
                DEF76E701C3B863C00CC7AF9 /* Main.storyboard */,
                DEF76E731C3B863C00CC7AF9 /* Assets.xcassets */,
                DEF76E751C3B863C00CC7AF9 /* LaunchScreen.storyboard */,
                DEF76E781C3B863C00CC7AF9 /* Info.plist */,
                DEF76E671C3B863C00CC7AF9 /* Supporting Files */,
            );
            path = Popover;
            sourceTree = "<group>";
        };
        DEF76E671C3B863C00CC7AF9 /* Supporting Files */ = {
            isa = PBXGroup;
            children = (
                DEF76E681C3B863C00CC7AF9 /* main.m */,
            );
            name = "Supporting Files";
            sourceTree = "<group>";
        };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
        DEF76E631C3B863C00CC7AF9 /* Popover */ = {
            isa = PBXNativeTarget;
            buildConfigurationList = DEF76E7B1C3B863C00CC7AF9 /* Build configuration list for PBXNativeTarget "Popover" */;
            buildPhases = (
                DEF76E601C3B863C00CC7AF9 /* Sources */,
                DEF76E611C3B863C00CC7AF9 /* Frameworks */,
                DEF76E621C3B863C00CC7AF9 /* Resources */,
            );
            buildRules = (
            );
            dependencies = (
            );
            name = Popover;
            productName = Popover;
            productReference = DEF76E641C3B863C00CC7AF9 /* Popover.app */;
            productType = "com.apple.product-type.application";
        };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
        DEF76E5C1C3B863C00CC7AF9 /* Project object */ = {
            isa = PBXProject;
            attributes = {
                LastUpgradeCheck = 0720;
                ORGANIZATIONNAME = lifution;
                TargetAttributes = {
                    DEF76E631C3B863C00CC7AF9 = {
                        CreatedOnToolsVersion = 7.2;
                        DevelopmentTeam = Q5668NKEBD;
                        ProvisioningStyle = Automatic;
                    };
                };
            };
            buildConfigurationList = DEF76E5F1C3B863C00CC7AF9 /* Build configuration list for PBXProject "Popover" */;
            compatibilityVersion = "Xcode 3.2";
            developmentRegion = English;
            hasScannedForEncodings = 0;
            knownRegions = (
                en,
                Base,
            );
            mainGroup = DEF76E5B1C3B863C00CC7AF9;
            productRefGroup = DEF76E651C3B863C00CC7AF9 /* Products */;
            projectDirPath = "";
            projectRoot = "";
            targets = (
                DEF76E631C3B863C00CC7AF9 /* Popover */,
            );
        };
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
        DEF76E621C3B863C00CC7AF9 /* Resources */ = {
            isa = PBXResourcesBuildPhase;
            buildActionMask = 2147483647;
            files = (
                DEF76E771C3B863C00CC7AF9 /* LaunchScreen.storyboard in Resources */,
                DEF76E741C3B863C00CC7AF9 /* Assets.xcassets in Resources */,
                DEF76E721C3B863C00CC7AF9 /* Main.storyboard in Resources */,
            );
            runOnlyForDeploymentPostprocessing = 0;
        };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
        DEF76E601C3B863C00CC7AF9 /* Sources */ = {
            isa = PBXSourcesBuildPhase;
            buildActionMask = 2147483647;
            files = (
                B057A05E1E013E180076287C /* PopoverViewCell.m in Sources */,
                DEF76E6F1C3B863C00CC7AF9 /* ViewController.m in Sources */,
                B057A05D1E013E180076287C /* PopoverView.m in Sources */,
                DEF76E6C1C3B863C00CC7AF9 /* AppDelegate.m in Sources */,
                DEF76E691C3B863C00CC7AF9 /* main.m in Sources */,
                B057A05C1E013E180076287C /* PopoverAction.m in Sources */,
            );
            runOnlyForDeploymentPostprocessing = 0;
        };
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
        DEF76E701C3B863C00CC7AF9 /* Main.storyboard */ = {
            isa = PBXVariantGroup;
            children = (
                DEF76E711C3B863C00CC7AF9 /* Base */,
            );
            name = Main.storyboard;
            sourceTree = "<group>";
        };
        DEF76E751C3B863C00CC7AF9 /* LaunchScreen.storyboard */ = {
            isa = PBXVariantGroup;
            children = (
                DEF76E761C3B863C00CC7AF9 /* Base */,
            );
            name = LaunchScreen.storyboard;
            sourceTree = "<group>";
        };
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
        DEF76E791C3B863C00CC7AF9 /* Debug */ = {
            isa = XCBuildConfiguration;
            buildSettings = {
                ALWAYS_SEARCH_USER_PATHS = NO;
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                CLANG_CXX_LIBRARY = "libc++";
                CLANG_ENABLE_MODULES = YES;
                CLANG_ENABLE_OBJC_ARC = YES;
                CLANG_WARN_BOOL_CONVERSION = YES;
                CLANG_WARN_CONSTANT_CONVERSION = YES;
                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                CLANG_WARN_EMPTY_BODY = YES;
                CLANG_WARN_ENUM_CONVERSION = YES;
                CLANG_WARN_INT_CONVERSION = YES;
                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                CLANG_WARN_UNREACHABLE_CODE = YES;
                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                COPY_PHASE_STRIP = NO;
                DEBUG_INFORMATION_FORMAT = dwarf;
                ENABLE_STRICT_OBJC_MSGSEND = YES;
                ENABLE_TESTABILITY = YES;
                GCC_C_LANGUAGE_STANDARD = gnu99;
                GCC_DYNAMIC_NO_PIC = NO;
                GCC_NO_COMMON_BLOCKS = YES;
                GCC_OPTIMIZATION_LEVEL = 0;
                GCC_PREPROCESSOR_DEFINITIONS = (
                    "DEBUG=1",
                    "$(inherited)",
                );
                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                GCC_WARN_UNDECLARED_SELECTOR = YES;
                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                GCC_WARN_UNUSED_FUNCTION = YES;
                GCC_WARN_UNUSED_VARIABLE = YES;
                IPHONEOS_DEPLOYMENT_TARGET = 7.0;
                MTL_ENABLE_DEBUG_INFO = YES;
                ONLY_ACTIVE_ARCH = YES;
                SDKROOT = iphoneos;
            };
            name = Debug;
        };
        DEF76E7A1C3B863C00CC7AF9 /* Release */ = {
            isa = XCBuildConfiguration;
            buildSettings = {
                ALWAYS_SEARCH_USER_PATHS = NO;
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                CLANG_CXX_LIBRARY = "libc++";
                CLANG_ENABLE_MODULES = YES;
                CLANG_ENABLE_OBJC_ARC = YES;
                CLANG_WARN_BOOL_CONVERSION = YES;
                CLANG_WARN_CONSTANT_CONVERSION = YES;
                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                CLANG_WARN_EMPTY_BODY = YES;
                CLANG_WARN_ENUM_CONVERSION = YES;
                CLANG_WARN_INT_CONVERSION = YES;
                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                CLANG_WARN_UNREACHABLE_CODE = YES;
                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                COPY_PHASE_STRIP = NO;
                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                ENABLE_NS_ASSERTIONS = NO;
                ENABLE_STRICT_OBJC_MSGSEND = YES;
                GCC_C_LANGUAGE_STANDARD = gnu99;
                GCC_NO_COMMON_BLOCKS = YES;
                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                GCC_WARN_UNDECLARED_SELECTOR = YES;
                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                GCC_WARN_UNUSED_FUNCTION = YES;
                GCC_WARN_UNUSED_VARIABLE = YES;
                IPHONEOS_DEPLOYMENT_TARGET = 7.0;
                MTL_ENABLE_DEBUG_INFO = NO;
                SDKROOT = iphoneos;
                VALIDATE_PRODUCT = YES;
            };
            name = Release;
        };
        DEF76E7C1C3B863C00CC7AF9 /* Debug */ = {
            isa = XCBuildConfiguration;
            buildSettings = {
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                DEVELOPMENT_TEAM = Q5668NKEBD;
                INFOPLIST_FILE = Popover/Info.plist;
                IPHONEOS_DEPLOYMENT_TARGET = 7.0;
                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
                PRODUCT_BUNDLE_IDENTIFIER = com.lifution.Popover;
                PRODUCT_NAME = "$(TARGET_NAME)";
            };
            name = Debug;
        };
        DEF76E7D1C3B863C00CC7AF9 /* Release */ = {
            isa = XCBuildConfiguration;
            buildSettings = {
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                DEVELOPMENT_TEAM = Q5668NKEBD;
                INFOPLIST_FILE = Popover/Info.plist;
                IPHONEOS_DEPLOYMENT_TARGET = 7.0;
                LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
                PRODUCT_BUNDLE_IDENTIFIER = com.lifution.Popover;
                PRODUCT_NAME = "$(TARGET_NAME)";
            };
            name = Release;
        };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
        DEF76E5F1C3B863C00CC7AF9 /* Build configuration list for PBXProject "Popover" */ = {
            isa = XCConfigurationList;
            buildConfigurations = (
                DEF76E791C3B863C00CC7AF9 /* Debug */,
                DEF76E7A1C3B863C00CC7AF9 /* Release */,
            );
            defaultConfigurationIsVisible = 0;
            defaultConfigurationName = Release;
        };
        DEF76E7B1C3B863C00CC7AF9 /* Build configuration list for PBXNativeTarget "Popover" */ = {
            isa = XCConfigurationList;
            buildConfigurations = (
                DEF76E7C1C3B863C00CC7AF9 /* Debug */,
                DEF76E7D1C3B863C00CC7AF9 /* Release */,
            );
            defaultConfigurationIsVisible = 0;
            defaultConfigurationName = Release;
        };
/* End XCConfigurationList section */
    };
    rootObject = DEF76E5C1C3B863C00CC7AF9 /* Project object */;
}
Popover/Popover.xcodeproj/project.xcworkspace/contents.xcworkspacedata
New file
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:Popover.xcodeproj">
   </FileRef>
</Workspace>
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/lifution.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/steven.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
Popover/Popover.xcodeproj/project.xcworkspace/xcuserdata/steven.xcuserdatad/WorkspaceSettings.xcsettings
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildLocationStyle</key>
    <string>UseAppPreferences</string>
    <key>CustomBuildLocationType</key>
    <string>RelativeToDerivedData</string>
    <key>DerivedDataLocationStyle</key>
    <string>Default</string>
    <key>IssueFilterStyle</key>
    <string>ShowActiveSchemeOnly</string>
    <key>LiveSourceIssuesEnabled</key>
    <true/>
</dict>
</plist>
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
New file
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   type = "1"
   version = "2.0">
   <Breakpoints>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "Popover/ViewController.m"
            timestampString = "504146319.593284"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "60"
            endingLineNumber = "60"
            landmarkName = "-leftBarItemAction:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "Popover/ViewController.m"
            timestampString = "504146324.272892"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "30"
            endingLineNumber = "30"
            landmarkName = "-QQActions"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "Popover/ViewController.m"
            timestampString = "504146330.570631"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "87"
            endingLineNumber = "87"
            landmarkName = "-showWithoutImage:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "Popover/ViewController.m"
            timestampString = "504146335.428569"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "80"
            endingLineNumber = "80"
            landmarkName = "-rightButtonAction:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "Popover/ViewController.m"
            timestampString = "504146713.885408"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "56"
            endingLineNumber = "56"
            landmarkName = "-buttonAction:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
   </Breakpoints>
</Bucket>
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/Popover.xcscheme
New file
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0810"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
               BuildableName = "Popover.app"
               BlueprintName = "Popover"
               ReferencedContainer = "container:Popover.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
Popover/Popover.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
New file
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>SchemeUserState</key>
    <dict>
        <key>Popover.xcscheme</key>
        <dict>
            <key>orderHint</key>
            <integer>0</integer>
        </dict>
    </dict>
    <key>SuppressBuildableAutocreation</key>
    <dict>
        <key>DEF76E631C3B863C00CC7AF9</key>
        <dict>
            <key>primary</key>
            <true/>
        </dict>
    </dict>
</dict>
</plist>
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   type = "1"
   version = "2.0">
</Bucket>
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcschemes/Popover.xcscheme
New file
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0720"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
               BuildableName = "Popover.app"
               BlueprintName = "Popover"
               ReferencedContainer = "container:Popover.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
Popover/Popover.xcodeproj/xcuserdata/lifution.xcuserdatad/xcschemes/xcschememanagement.plist
New file
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>SchemeUserState</key>
    <dict>
        <key>Popover.xcscheme</key>
        <dict>
            <key>orderHint</key>
            <integer>0</integer>
        </dict>
    </dict>
    <key>SuppressBuildableAutocreation</key>
    <dict>
        <key>DEF76E631C3B863C00CC7AF9</key>
        <dict>
            <key>primary</key>
            <true/>
        </dict>
    </dict>
</dict>
</plist>
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   type = "1"
   version = "2.0">
</Bucket>
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/Popover.xcscheme
New file
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0810"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
               BuildableName = "Popover.app"
               BlueprintName = "Popover"
               ReferencedContainer = "container:Popover.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "DEF76E631C3B863C00CC7AF9"
            BuildableName = "Popover.app"
            BlueprintName = "Popover"
            ReferencedContainer = "container:Popover.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
Popover/Popover.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/xcschememanagement.plist
New file
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>SchemeUserState</key>
    <dict>
        <key>Popover.xcscheme</key>
        <dict>
            <key>orderHint</key>
            <integer>0</integer>
        </dict>
    </dict>
    <key>SuppressBuildableAutocreation</key>
    <dict>
        <key>DEF76E631C3B863C00CC7AF9</key>
        <dict>
            <key>primary</key>
            <true/>
        </dict>
    </dict>
</dict>
</plist>
Popover/Popover/AppDelegate.h
New file
@@ -0,0 +1,17 @@
//
//  AppDelegate.h
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
Popover/Popover/AppDelegate.m
New file
@@ -0,0 +1,46 @@
//
//  AppDelegate.m
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
    return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Contents.json
New file
@@ -0,0 +1,74 @@
{
  "images" : [
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "Icon-Notification@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "Icon-Notification@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-Small.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-Small@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-Small@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-Small-40@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-Small-40@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "Icon.png",
      "scale" : "1x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "Icon@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon.png
Popover/Popover/Assets.xcassets/AppIcon.appiconset/Icon@2x.png
Popover/Popover/Assets.xcassets/Contents.json
New file
@@ -0,0 +1,6 @@
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/contacts_add_friend.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "contacts_add_friend@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/contacts_add_friend.imageset/contacts_add_friend@2x.png
Popover/Popover/Assets.xcassets/contacts_add_money.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "contacts_add_money@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/contacts_add_money.imageset/contacts_add_money@2x.png
Popover/Popover/Assets.xcassets/contacts_add_newmessage.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "contacts_add_newmessage@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/contacts_add_newmessage.imageset/contacts_add_newmessage@2x.png
Popover/Popover/Assets.xcassets/contacts_add_scan.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "contacts_add_scan@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/contacts_add_scan.imageset/contacts_add_scan@2x.png
Popover/Popover/Assets.xcassets/navigationItem_menu.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "navigationItem_menu@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/navigationItem_menu.imageset/navigationItem_menu@2x.png
Popover/Popover/Assets.xcassets/right_menu_QR.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "right_menu_QR@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/right_menu_QR.imageset/right_menu_QR@2x.png
Popover/Popover/Assets.xcassets/right_menu_addFri.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "right_menu_addFri@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/right_menu_addFri.imageset/right_menu_addFri@2x.png
Popover/Popover/Assets.xcassets/right_menu_facetoface.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "right_menu_facetoface@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/right_menu_facetoface.imageset/right_menu_facetoface@2x.png
Popover/Popover/Assets.xcassets/right_menu_multichat.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "right_menu_multichat@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/right_menu_multichat.imageset/right_menu_multichat@2x.png
Popover/Popover/Assets.xcassets/right_menu_payMoney.imageset/Contents.json
New file
@@ -0,0 +1,21 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "right_menu_payMoney@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
Popover/Popover/Assets.xcassets/right_menu_payMoney.imageset/right_menu_payMoney@2x.png
Popover/Popover/Base.lproj/LaunchScreen.storyboard
New file
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>
Popover/Popover/Base.lproj/Main.storyboard
New file
@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="QBF-Rp-PB9">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Navigation Controller-->
        <scene sceneID="KFp-Vm-K4s">
            <objects>
                <navigationController id="QBF-Rp-PB9" sceneMemberID="viewController">
                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="Ozy-CH-Lu2">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <color key="barTintColor" red="0.1176470588" green="0.66666666669999997" blue="0.94509803920000002" alpha="1" colorSpace="calibratedRGB"/>
                        <textAttributes key="titleTextAttributes">
                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        </textAttributes>
                    </navigationBar>
                    <connections>
                        <segue destination="geS-fr-ReB" kind="relationship" relationship="rootViewController" id="EMz-iF-tU4"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="avt-Ud-Iy2" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="266" y="107"/>
        </scene>
        <!--Popover-->
        <scene sceneID="DAI-sZ-Mja">
            <objects>
                <viewController storyboardIdentifier="ViewController" id="geS-fr-ReB" customClass="ViewController" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="ixD-XH-j9U"/>
                        <viewControllerLayoutGuide type="bottom" id="Fy8-B8-FAY"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="4BN-3b-jmf">
                        <rect key="frame" x="0.0" y="64" width="375" height="603"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CC4-QJ-l9N">
                                <rect key="frame" x="132.5" y="40" width="110" height="32"/>
                                <color key="backgroundColor" red="0.1176470588" green="0.66666666669999997" blue="0.94509803920000002" alpha="1" colorSpace="calibratedRGB"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="110" id="8jt-SV-sGC"/>
                                    <constraint firstAttribute="height" constant="32" id="nPy-0w-reU"/>
                                </constraints>
                                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
                                <state key="normal" title="showPopover">
                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                </state>
                                <userDefinedRuntimeAttributes>
                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                        <integer key="value" value="5"/>
                                    </userDefinedRuntimeAttribute>
                                    <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                </userDefinedRuntimeAttributes>
                                <connections>
                                    <action selector="buttonAction:" destination="geS-fr-ReB" eventType="touchUpInside" id="5Fb-xu-qiH"/>
                                </connections>
                            </button>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="A0b-Ah-o6l">
                                <rect key="frame" x="10" y="531" width="110" height="32"/>
                                <color key="backgroundColor" red="1" green="0.50196081400000003" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="110" id="3Y9-zp-TGA"/>
                                    <constraint firstAttribute="height" constant="32" id="Lqd-NN-Sqw"/>
                                </constraints>
                                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
                                <state key="normal" title="showPopover">
                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                </state>
                                <userDefinedRuntimeAttributes>
                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                        <integer key="value" value="5"/>
                                    </userDefinedRuntimeAttribute>
                                    <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                </userDefinedRuntimeAttributes>
                                <connections>
                                    <action selector="buttonAction:" destination="geS-fr-ReB" eventType="touchUpInside" id="EPh-gE-xUy"/>
                                </connections>
                            </button>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qFV-Z6-rzD">
                                <rect key="frame" x="255" y="531" width="110" height="32"/>
                                <color key="backgroundColor" red="0.0" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="32" id="OtP-Ah-fdc"/>
                                    <constraint firstAttribute="width" constant="110" id="xIG-PH-GXB"/>
                                </constraints>
                                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
                                <state key="normal" title="showPopover">
                                    <color key="titleColor" cocoaTouchSystemColor="darkTextColor"/>
                                </state>
                                <userDefinedRuntimeAttributes>
                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                        <integer key="value" value="5"/>
                                    </userDefinedRuntimeAttribute>
                                    <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                </userDefinedRuntimeAttributes>
                                <connections>
                                    <action selector="buttonAction:" destination="geS-fr-ReB" eventType="touchUpInside" id="NsQ-gX-bTF"/>
                                </connections>
                            </button>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="你选择了" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1cc-Xs-eD0">
                                <rect key="frame" x="154.5" y="292" width="65.5" height="19.5"/>
                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="944-J4-LAc">
                                <rect key="frame" x="187" y="321.5" width="0.0" height="0.0"/>
                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                <color key="textColor" red="0.98823529409999999" green="0.0" blue="0.0039215686269999999" alpha="1" colorSpace="calibratedRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HGk-11-wXz">
                                <rect key="frame" x="132" y="471" width="110" height="32"/>
                                <color key="backgroundColor" red="1" green="0.0" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="110" id="N4g-ZW-09w"/>
                                    <constraint firstAttribute="height" constant="32" id="ude-Je-Gk3"/>
                                </constraints>
                                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
                                <state key="normal" title="showPopover">
                                    <color key="titleColor" red="0.0" green="0.0" blue="0.50196081400000003" alpha="1" colorSpace="calibratedRGB"/>
                                </state>
                                <userDefinedRuntimeAttributes>
                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                        <integer key="value" value="5"/>
                                    </userDefinedRuntimeAttribute>
                                    <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                </userDefinedRuntimeAttributes>
                                <connections>
                                    <action selector="showWithoutImage:" destination="geS-fr-ReB" eventType="touchUpInside" id="1EK-Wb-VAI"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="CC4-QJ-l9N" firstAttribute="centerX" secondItem="4BN-3b-jmf" secondAttribute="centerX" id="4in-U8-RTN"/>
                            <constraint firstItem="1cc-Xs-eD0" firstAttribute="centerY" secondItem="4BN-3b-jmf" secondAttribute="centerY" id="Acf-fv-URZ"/>
                            <constraint firstItem="1cc-Xs-eD0" firstAttribute="centerX" secondItem="4BN-3b-jmf" secondAttribute="centerX" id="ED4-5N-nn1"/>
                            <constraint firstItem="944-J4-LAc" firstAttribute="centerX" secondItem="4BN-3b-jmf" secondAttribute="centerX" id="Esz-eK-vIz"/>
                            <constraint firstItem="CC4-QJ-l9N" firstAttribute="top" secondItem="ixD-XH-j9U" secondAttribute="bottom" constant="40" id="IrW-Yt-MNG"/>
                            <constraint firstItem="Fy8-B8-FAY" firstAttribute="top" secondItem="HGk-11-wXz" secondAttribute="bottom" constant="100" id="M3e-IM-osS"/>
                            <constraint firstItem="A0b-Ah-o6l" firstAttribute="leading" secondItem="4BN-3b-jmf" secondAttribute="leading" constant="10" id="UTc-Ff-sfV"/>
                            <constraint firstItem="944-J4-LAc" firstAttribute="top" secondItem="1cc-Xs-eD0" secondAttribute="bottom" constant="10" id="UrE-SB-p9x"/>
                            <constraint firstItem="Fy8-B8-FAY" firstAttribute="top" secondItem="qFV-Z6-rzD" secondAttribute="bottom" constant="40" id="WvE-4Z-Zy5"/>
                            <constraint firstAttribute="trailing" secondItem="qFV-Z6-rzD" secondAttribute="trailing" constant="10" id="bJJ-Jq-7I8"/>
                            <constraint firstItem="HGk-11-wXz" firstAttribute="centerX" secondItem="4BN-3b-jmf" secondAttribute="centerX" id="maw-7u-V55"/>
                            <constraint firstItem="Fy8-B8-FAY" firstAttribute="top" secondItem="A0b-Ah-o6l" secondAttribute="bottom" constant="40" id="y51-UC-69M"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" title="Popover" id="xXS-78-Yrl">
                        <barButtonItem key="leftBarButtonItem" image="navigationItem_menu" id="PKd-xW-kEH">
                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                            <connections>
                                <action selector="leftBarItemAction:" destination="geS-fr-ReB" id="CYo-d1-lzq"/>
                            </connections>
                        </barButtonItem>
                        <barButtonItem key="rightBarButtonItem" id="HkD-ni-VFq">
                            <button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="yDx-1B-vCI">
                                <rect key="frame" x="334" y="9" width="25" height="25"/>
                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <state key="normal" image="navigationItem_menu"/>
                                <connections>
                                    <action selector="rightButtonAction:" destination="geS-fr-ReB" eventType="touchUpInside" id="eVe-39-zS7"/>
                                </connections>
                            </button>
                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        </barButtonItem>
                    </navigationItem>
                    <connections>
                        <outlet property="noticeLabel" destination="944-J4-LAc" id="DfQ-z5-DtL"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="rCP-RK-tfJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="974" y="107"/>
        </scene>
    </scenes>
    <resources>
        <image name="navigationItem_menu" width="20" height="20"/>
    </resources>
</document>
Popover/Popover/Info.plist
New file
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UIStatusBarHidden</key>
    <true/>
    <key>UIStatusBarStyle</key>
    <string>UIStatusBarStyleLightContent</string>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
</dict>
</plist>
Popover/Popover/PopoverView/PopoverAction.h
New file
@@ -0,0 +1,28 @@
//
//  PopoverAction.h
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, PopoverViewStyle)
{
    PopoverViewStyleDefault = 0, // 默认风格, 白色
    PopoverViewStyleDark, // 黑色风格
};
@interface PopoverAction : NSObject
@property (nonatomic, strong, readonly) UIImage *image; ///< 图标 (建议使用 60pix*60pix 的图片)
@property (nonatomic, copy, readonly) NSString *title; ///< 标题
@property (nonatomic, copy, readonly) void(^handler)(PopoverAction *action); ///< 选择回调, 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
+ (instancetype)actionWithTitle:(NSString *)title handler:(void (^)(PopoverAction *action))handler;
+ (instancetype)actionWithImage:(UIImage *)image title:(NSString *)title handler:(void (^)(PopoverAction *action))handler;
@end
Popover/Popover/PopoverView/PopoverAction.m
New file
@@ -0,0 +1,34 @@
//
//  PopoverAction.m
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverAction.h"
@interface PopoverAction ()
@property (nonatomic, strong, readwrite) UIImage *image; ///< 图标
@property (nonatomic, copy, readwrite) NSString *title; ///< 风格
@property (nonatomic, copy, readwrite) void(^handler)(PopoverAction *action); ///< 选择回调
@end
@implementation PopoverAction
+ (instancetype)actionWithTitle:(NSString *)title handler:(void (^)(PopoverAction *action))handler {
    return [self actionWithImage:nil title:title handler:handler];
}
+ (instancetype)actionWithImage:(UIImage *)image title:(NSString *)title handler:(void (^)(PopoverAction *action))handler {
    PopoverAction *action = [[self alloc] init];
    action.image = image;
    action.title = title ? : @"";
    action.handler = handler ? : NULL;
    return action;
}
@end
Popover/Popover/PopoverView/PopoverView.h
New file
@@ -0,0 +1,32 @@
//
//  PopoverView.h
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PopoverAction.h"
@interface PopoverView : UIView
@property (nonatomic, assign) BOOL hideAfterTouchOutside; ///< 是否开启点击外部隐藏弹窗, 默认为YES.
@property (nonatomic, assign) BOOL showShade; ///< 是否显示阴影, 如果为YES则弹窗背景为半透明的阴影层, 否则为透明, 默认为NO.
@property (nonatomic, assign) PopoverViewStyle style; ///< 弹出窗风格, 默认为 PopoverViewStyleDefault(白色).
+ (instancetype)popoverView;
/*! @brief 指向指定的View来显示弹窗
 *  @param pointView 箭头指向的View
 *  @param actions   动作对象集合<PopoverAction>
 */
- (void)showToView:(UIView *)pointView withActions:(NSArray<PopoverAction *> *)actions;
/*! @brief 指向指定的点来显示弹窗
 *  @param toPoint 箭头指向的点(这个点的坐标需按照keyWindow的坐标为参照)
 *  @param actions 动作对象集合<PopoverAction>
 */
- (void)showToPoint:(CGPoint)toPoint withActions:(NSArray<PopoverAction *> *)actions;
@end
Popover/Popover/PopoverView/PopoverView.m
New file
@@ -0,0 +1,398 @@
//
//  PopoverView.m
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverView.h"
#import "PopoverViewCell.h"
static float const kPopoverViewMargin = 8.f; ///< 边距
static float const kPopoverViewCellHeight = 40.f; ///< cell指定高度
static float const kPopoverViewArrowHeight = 13.f; ///< 箭头高度
// convert degrees to radians
float DegreesToRadians(float angle) {
    return angle*M_PI/180;
}
@interface PopoverView () <UITableViewDelegate, UITableViewDataSource>
#pragma mark - UI
@property (nonatomic, weak) UIWindow *keyWindow; ///< 当前窗口
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *shadeView; ///< 遮罩层
@property (nonatomic, weak) CAShapeLayer *borderLayer; ///< 边框Layer
@property (nonatomic, weak) UITapGestureRecognizer *tapGesture; ///< 点击背景阴影的手势
#pragma mark - Data
@property (nonatomic, copy) NSArray<PopoverAction *> *actions;
@property (nonatomic, assign) CGFloat windowWidth; ///< 窗口宽度
@property (nonatomic, assign) CGFloat windowHeight; ///< 窗口高度
@property (nonatomic, assign) BOOL isUpward; ///< 箭头指向, YES为向上, 反之为向下, 默认为YES.
@end
@implementation PopoverView
#pragma mark - Lift Cycle
- (instancetype)initWithFrame:(CGRect)frame
{
    if (!(self = [super initWithFrame:frame])) return nil;
    [self initialize];
    return self;
}
- (void)awakeFromNib {
    [super awakeFromNib];
    [self initialize];
}
- (void)layoutSubviews
{
    [super layoutSubviews];
    _tableView.frame = CGRectMake(0, _isUpward ? kPopoverViewArrowHeight : 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - kPopoverViewArrowHeight);
}
#pragma mark - Setter
- (void)setHideAfterTouchOutside:(BOOL)hideAfterTouchOutside
{
    _hideAfterTouchOutside = hideAfterTouchOutside;
    _tapGesture.enabled = _hideAfterTouchOutside;
}
- (void)setShowShade:(BOOL)showShade
{
    _showShade = showShade;
    _shadeView.backgroundColor = _showShade ? [UIColor colorWithWhite:0.f alpha:0.18f] : [UIColor clearColor];
    if (_borderLayer) {
        _borderLayer.strokeColor = _showShade ? [UIColor clearColor].CGColor : _tableView.separatorColor.CGColor;
    }
}
- (void)setStyle:(PopoverViewStyle)style
{
    _style = style;
    _tableView.separatorColor = [PopoverViewCell bottomLineColorForStyle:_style];
    if (_style == PopoverViewStyleDefault)
    {
        self.backgroundColor = [UIColor whiteColor];
    }
    else
    {
        self.backgroundColor = [UIColor colorWithRed:0.29 green:0.29 blue:0.29 alpha:1.00];
    }
}
#pragma mark - Private
/*! @brief 初始化相关 */
- (void)initialize {
    // data
    _actions = @[];
    _isUpward = YES;
    _style = PopoverViewStyleDefault;
    // current view
    self.backgroundColor = [UIColor whiteColor];
    // keyWindow
    _keyWindow = [UIApplication sharedApplication].keyWindow;
    _windowWidth = CGRectGetWidth(_keyWindow.bounds);
    _windowHeight = CGRectGetHeight(_keyWindow.bounds);
    // shadeView
    _shadeView = [[UIView alloc] initWithFrame:_keyWindow.bounds];
    [self setShowShade:NO];
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
    [_shadeView addGestureRecognizer:tapGesture];
    _tapGesture = tapGesture;
    // tableView
    _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    _tableView.scrollEnabled = NO;
    _tableView.showsVerticalScrollIndicator = NO;
    _tableView.backgroundColor = [UIColor clearColor];
    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    _tableView.separatorColor = [PopoverViewCell bottomLineColorForStyle:_style];
    [self addSubview:_tableView];
}
/*! @brief 显示弹窗指向某个点,  */
- (void)showToPoint:(CGPoint)toPoint {
    NSAssert(_actions.count > 0, @"actions must not be nil or empty !");
    // 截取弹窗时相关数据
    float arrowWidth = 28;
    float cornerRadius = 6.f;
    float arrowCornerRadius = 2.5f;
    float arrowBottomCornerRadius = 4.f;
    // 如果箭头指向的点过于偏左或者过于偏右则需要重新调整箭头 x 轴的坐标
    CGFloat minHorizontalEdge = kPopoverViewMargin + cornerRadius + arrowWidth/2 + 2;
    if (toPoint.x < minHorizontalEdge) {
        toPoint.x = minHorizontalEdge;
    }
    if (_windowWidth - toPoint.x < minHorizontalEdge) {
        toPoint.x = _windowWidth - minHorizontalEdge;
    }
    // 遮罩层
    _shadeView.alpha = 0.f;
    [_keyWindow addSubview:_shadeView];
    // 刷新数据以获取具体的ContentSize
    [_tableView reloadData];
    // 根据刷新后的ContentSize和箭头指向方向来设置当前视图的frame
    CGFloat currentW = [self calculateMaxWidth]; // 宽度通过计算获取最大值
    CGFloat currentH = _tableView.contentSize.height + kPopoverViewArrowHeight;
    // 限制最高高度, 免得选项太多时超出屏幕
    CGFloat maxHeight = _isUpward ? (_windowHeight - toPoint.y - kPopoverViewMargin) : (toPoint.y - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame));
    if (currentH > maxHeight) { // 如果弹窗高度大于最大高度的话则限制弹窗高度等于最大高度并允许tableView滑动.
        currentH = maxHeight;
        _tableView.scrollEnabled = YES;
        if (!_isUpward) { // 箭头指向下则移动到最后一行
            [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_actions.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
        }
    }
    CGFloat currentX = toPoint.x - currentW/2, currentY = toPoint.y;
    // x: 窗口靠左
    if (toPoint.x <= currentW/2 + kPopoverViewMargin) {
        currentX = kPopoverViewMargin;
    }
    // x: 窗口靠右
    if (_windowWidth - toPoint.x <= currentW/2 + kPopoverViewMargin) {
        currentX = _windowWidth - kPopoverViewMargin - currentW;
    }
    // y: 箭头向下
    if (!_isUpward) {
        currentY = toPoint.y - currentH;
    }
    self.frame = CGRectMake(currentX, currentY, currentW, currentH);
    // 截取箭头
    CGPoint arrowPoint = CGPointMake(toPoint.x - CGRectGetMinX(self.frame), _isUpward ? 0 : currentH); // 箭头顶点在当前视图的坐标
    CGFloat maskTop = _isUpward ? kPopoverViewArrowHeight : 0; // 顶部Y值
    CGFloat maskBottom = _isUpward ? currentH : currentH - kPopoverViewArrowHeight; // 底部Y值
    UIBezierPath *maskPath = [UIBezierPath bezierPath];
    // 左上圆角
    [maskPath moveToPoint:CGPointMake(0, cornerRadius + maskTop)];
    [maskPath addArcWithCenter:CGPointMake(cornerRadius, cornerRadius + maskTop)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(180)
                      endAngle:DegreesToRadians(270)
                     clockwise:YES];
    // 箭头向上时的箭头位置
    if (_isUpward) {
        [maskPath addLineToPoint:CGPointMake(arrowPoint.x - arrowWidth/2, kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowCornerRadius, arrowCornerRadius)
                         controlPoint:CGPointMake(arrowPoint.x - arrowWidth/2 + arrowBottomCornerRadius, kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowCornerRadius, arrowCornerRadius)
                         controlPoint:arrowPoint];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowWidth/2, kPopoverViewArrowHeight)
                         controlPoint:CGPointMake(arrowPoint.x + arrowWidth/2 - arrowBottomCornerRadius, kPopoverViewArrowHeight)];
    }
    // 右上圆角
    [maskPath addLineToPoint:CGPointMake(currentW - cornerRadius, maskTop)];
    [maskPath addArcWithCenter:CGPointMake(currentW - cornerRadius, maskTop + cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(270)
                      endAngle:DegreesToRadians(0)
                     clockwise:YES];
    // 右下圆角
    [maskPath addLineToPoint:CGPointMake(currentW, maskBottom - cornerRadius)];
    [maskPath addArcWithCenter:CGPointMake(currentW - cornerRadius, maskBottom - cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(0)
                      endAngle:DegreesToRadians(90)
                     clockwise:YES];
    // 箭头向下时的箭头位置
    if (!_isUpward) {
        [maskPath addLineToPoint:CGPointMake(arrowPoint.x + arrowWidth/2, currentH - kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowCornerRadius, currentH - arrowCornerRadius)
                         controlPoint:CGPointMake(arrowPoint.x + arrowWidth/2 - arrowBottomCornerRadius, currentH - kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowCornerRadius, currentH - arrowCornerRadius)
                         controlPoint:arrowPoint];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowWidth/2, currentH - kPopoverViewArrowHeight)
                         controlPoint:CGPointMake(arrowPoint.x - arrowWidth/2 + arrowBottomCornerRadius, currentH - kPopoverViewArrowHeight)];
    }
    // 左下圆角
    [maskPath addLineToPoint:CGPointMake(cornerRadius, maskBottom)];
    [maskPath addArcWithCenter:CGPointMake(cornerRadius, maskBottom - cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(90)
                      endAngle:DegreesToRadians(180)
                     clockwise:YES];
    [maskPath closePath];
    // 截取圆角和箭头
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;
    maskLayer.path = maskPath.CGPath;
    self.layer.mask = maskLayer;
    // 边框 (只有在不显示半透明阴影层时才设置边框线条)
    if (!_showShade) {
        CAShapeLayer *borderLayer = [CAShapeLayer layer];
        borderLayer.frame = self.bounds;
        borderLayer.path = maskPath.CGPath;
        borderLayer.lineWidth = 1;
        borderLayer.fillColor = [UIColor clearColor].CGColor;
        borderLayer.strokeColor = _tableView.separatorColor.CGColor;
        [self.layer addSublayer:borderLayer];
        _borderLayer = borderLayer;
    }
    [_keyWindow addSubview:self];
    // 弹出动画
    CGRect oldFrame = self.frame;
    self.layer.anchorPoint = CGPointMake(arrowPoint.x/currentW, _isUpward ? 0.f : 1.f);
    self.frame = oldFrame;
    self.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
    [UIView animateWithDuration:0.25f animations:^{
        self.transform = CGAffineTransformIdentity;
        _shadeView.alpha = 1.f;
    }];
}
/*! @brief 计算最大宽度 */
- (CGFloat)calculateMaxWidth {
    CGFloat maxWidth = 0.f, titleLeftEdge = 0.f, imageWidth = 0.f, imageMaxHeight = kPopoverViewCellHeight - PopoverViewCellVerticalMargin*2;
    CGSize imageSize = CGSizeZero;
    UIFont *titleFont = [PopoverViewCell titleFont];
    for (PopoverAction *action in _actions) {
        imageWidth = 0.f;
        titleLeftEdge = 0.f;
        if (action.image) { // 存在图片则根据图片size和图片最大高度来重新计算图片宽度
            titleLeftEdge = PopoverViewCellTitleLeftEdge; // 有图片时标题才有左边的边距
            imageSize = action.image.size;
            if (imageSize.height > imageMaxHeight) {
                imageWidth = imageMaxHeight*imageSize.width/imageSize.height;
            } else {
                imageWidth = imageSize.width;
            }
        }
        CGFloat titleWidth;
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) { // iOS7及往后版本
            titleWidth = [action.title sizeWithAttributes:@{NSFontAttributeName : titleFont}].width;
        } else { // iOS6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
            titleWidth = [action.title sizeWithFont:titleFont].width;
#pragma GCC diagnostic pop
        }
        CGFloat contentWidth = PopoverViewCellHorizontalMargin*2 + imageWidth + titleLeftEdge + titleWidth;
        if (contentWidth > maxWidth) {
            maxWidth = ceil(contentWidth); // 获取最大宽度时需使用进一取法, 否则Cell中没有图片时会可能导致标题显示不完整.
        }
    }
    // 如果最大宽度大于(窗口宽度 - kPopoverViewMargin*2)则限制最大宽度等于(窗口宽度 - kPopoverViewMargin*2)
    if (maxWidth > CGRectGetWidth(_keyWindow.bounds) - kPopoverViewMargin*2) {
        maxWidth = CGRectGetWidth(_keyWindow.bounds) - kPopoverViewMargin*2;
    }
    return maxWidth;
}
/*! @brief 点击外部隐藏弹窗 */
- (void)hide {
    [UIView animateWithDuration:0.25f animations:^{
        self.alpha = 0.f;
        _shadeView.alpha = 0.f;
        self.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
    } completion:^(BOOL finished) {
        [_shadeView removeFromSuperview];
        [self removeFromSuperview];
    }];
}
#pragma mark - Public
+ (instancetype)popoverView {
    return [[self alloc] init];
}
/*! @brief 指向指定的View来显示弹窗 */
- (void)showToView:(UIView *)pointView withActions:(NSArray<PopoverAction *> *)actions
{
    // 判断 pointView 是偏上还是偏下
    CGRect pointViewRect = [pointView.superview convertRect:pointView.frame toView:_keyWindow];
    CGFloat pointViewUpLength = CGRectGetMinY(pointViewRect);
    CGFloat pointViewDownLength = _windowHeight - CGRectGetMaxY(pointViewRect);
    // 弹窗箭头指向的点
    CGPoint toPoint = CGPointMake(CGRectGetMidX(pointViewRect), 0);
    // 弹窗在 pointView 顶部
    if (pointViewUpLength > pointViewDownLength)
    {
        toPoint.y = pointViewUpLength - 5;
    }
    // 弹窗在 pointView 底部
    else
    {
        toPoint.y = CGRectGetMaxY(pointViewRect) + 5;
    }
    // 箭头指向方向
    _isUpward = pointViewUpLength <= pointViewDownLength;
    _actions = [actions copy];
    [self showToPoint:toPoint];
}
/*! @brief 指向指定的点来显示弹窗 */
- (void)showToPoint:(CGPoint)toPoint withActions:(NSArray<PopoverAction *> *)actions {
    _actions = [actions copy];
    // 计算箭头指向方向
    _isUpward = toPoint.y <= _windowHeight - toPoint.y;
    [self showToPoint:toPoint];
}
#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _actions.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return kPopoverViewCellHeight;
}
static NSString *kPopoverCellIdentifier = @"kPopoverCellIdentifier";
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    PopoverViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPopoverCellIdentifier];
    if (!cell)
    {
        cell = [[PopoverViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kPopoverCellIdentifier];
    }
    [cell setAction:_actions[indexPath.row]];
    [cell showBottomLine: indexPath.row < _actions.count - 1];
    cell.style = _style;
    return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [UIView animateWithDuration:0.25f animations:^{
        self.alpha = 0.f;
        _shadeView.alpha = 0.f;
    } completion:^(BOOL finished) {
        PopoverAction *action = _actions[indexPath.row];
        action.handler ? action.handler(action) : NULL;
        _actions = nil;
        [_shadeView removeFromSuperview];
        [self removeFromSuperview];
    }];
}
@end
Popover/Popover/PopoverView/PopoverViewCell.h
New file
@@ -0,0 +1,34 @@
//
//  PopoverViewCell.h
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PopoverAction.h"
UIKIT_EXTERN float const PopoverViewCellHorizontalMargin; ///< 水平间距边距
UIKIT_EXTERN float const PopoverViewCellVerticalMargin; ///< 垂直边距
UIKIT_EXTERN float const PopoverViewCellTitleLeftEdge; ///< 标题左边边距
@class PopoverAction;
@interface PopoverViewCell : UITableViewCell
@property (nonatomic, assign) PopoverViewStyle style;
/*! @brief 标题字体
 */
+ (UIFont *)titleFont;
/*! @brief 底部线条颜色
 */
+ (UIColor *)bottomLineColorForStyle:(PopoverViewStyle)style;
- (void)setAction:(PopoverAction *)action;
- (void)showBottomLine:(BOOL)show;
@end
Popover/Popover/PopoverView/PopoverViewCell.m
New file
@@ -0,0 +1,109 @@
//
//  PopoverViewCell.m
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverViewCell.h"
// extern
float const PopoverViewCellHorizontalMargin = 15.f; ///< 水平边距
float const PopoverViewCellVerticalMargin = 3.f; ///< 垂直边距
float const PopoverViewCellTitleLeftEdge = 8.f; ///< 标题左边边距
@interface PopoverViewCell ()
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, weak) UIView *bottomLine;
@end
@implementation PopoverViewCell
#pragma mark - Life Cycle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;
    self.backgroundColor = [UIColor clearColor];
    self.contentView.backgroundColor = self.backgroundColor;
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    // initialize
    [self initialize];
    return self;
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
    [super setHighlighted:highlighted animated:animated];
    if (highlighted) {
        self.backgroundColor = _style == PopoverViewStyleDefault ? [UIColor colorWithRed:0.90 green:0.90 blue:0.90 alpha:1.00] : [UIColor colorWithRed:0.23 green:0.23 blue:0.23 alpha:1.00];
    } else {
        [UIView animateWithDuration:0.3f animations:^{
            self.backgroundColor = [UIColor clearColor];
        }];
    }
}
#pragma mark - Setter
- (void)setStyle:(PopoverViewStyle)style {
    _style = style;
    _bottomLine.backgroundColor = [self.class bottomLineColorForStyle:style];
    if (_style == PopoverViewStyleDefault) {
        [_button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
    } else {
        [_button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
    }
}
#pragma mark - Private
// 初始化
- (void)initialize {
    // UI
    _button = [UIButton buttonWithType:UIButtonTypeCustom];
    _button.userInteractionEnabled = NO; // has no use for UserInteraction.
    _button.translatesAutoresizingMaskIntoConstraints = NO;
    _button.titleLabel.font = [self.class titleFont];
    _button.backgroundColor = self.contentView.backgroundColor;
    _button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
    [_button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
    [self.contentView addSubview:_button];
    // Constraint
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[_button]-margin-|" options:kNilOptions metrics:@{@"margin" : @(PopoverViewCellHorizontalMargin)} views:NSDictionaryOfVariableBindings(_button)]];
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-margin-[_button]-margin-|" options:kNilOptions metrics:@{@"margin" : @(PopoverViewCellVerticalMargin)} views:NSDictionaryOfVariableBindings(_button)]];
    // 底部线条
    UIView *bottomLine = [[UIView alloc] init];
    bottomLine.backgroundColor = [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:1.00];
    bottomLine.translatesAutoresizingMaskIntoConstraints = NO;
    [self.contentView addSubview:bottomLine];
    _bottomLine = bottomLine;
    // Constraint
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[bottomLine]|" options:kNilOptions metrics:nil views:NSDictionaryOfVariableBindings(bottomLine)]];
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomLine(lineHeight)]|" options:kNilOptions metrics:@{@"lineHeight" : @(1/[UIScreen mainScreen].scale)} views:NSDictionaryOfVariableBindings(bottomLine)]];
}
#pragma mark - Public
/*! @brief 标题字体 */
+ (UIFont *)titleFont
{
    return [UIFont systemFontOfSize:15.f];
}
/*! @brief 底部线条颜色 */
+ (UIColor *)bottomLineColorForStyle:(PopoverViewStyle)style
{
    return style == PopoverViewStyleDefault ? [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:1.00] : [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1.00];
}
- (void)setAction:(PopoverAction *)action
{
    [_button setImage:action.image forState:UIControlStateNormal];
    [_button setTitle:action.title forState:UIControlStateNormal];
    _button.titleEdgeInsets = action.image ? UIEdgeInsetsMake(0, PopoverViewCellTitleLeftEdge, 0, -PopoverViewCellTitleLeftEdge) : UIEdgeInsetsZero;
}
- (void)showBottomLine:(BOOL)show {
    _bottomLine.hidden = !show;
}
@end
Popover/Popover/ViewController.h
New file
@@ -0,0 +1,15 @@
//
//  ViewController.h
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
Popover/Popover/ViewController.m
New file
@@ -0,0 +1,112 @@
//
//  ViewController.m
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "ViewController.h"
#import "PopoverView.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *noticeLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (NSArray<PopoverAction *> *)QQActions
{
    // 发起多人聊天 action
    PopoverAction *multichatAction = [PopoverAction actionWithImage:[UIImage imageNamed:@"right_menu_multichat"] title:@"发起多人聊天" handler:^(PopoverAction *action) {
#pragma mark - 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
        _noticeLabel.text = action.title;
    }];
    // 加好友 action
    PopoverAction *addFriAction = [PopoverAction actionWithImage:[UIImage imageNamed:@"right_menu_addFri"] title:@"加好友" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    // 扫一扫 action
    PopoverAction *QRAction = [PopoverAction actionWithImage:[UIImage imageNamed:@"right_menu_QR"] title:@"扫一扫" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    // 面对面快传 action
    PopoverAction *facetofaceAction = [PopoverAction actionWithImage:[UIImage imageNamed:@"right_menu_facetoface"] title:@"面对面快传" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    // 付款 action
    PopoverAction *payMoneyAction = [PopoverAction actionWithImage:[UIImage imageNamed:@"right_menu_payMoney"] title:@"付款" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    return @[multichatAction, addFriAction, QRAction, facetofaceAction, payMoneyAction];
}
- (IBAction)buttonAction:(UIButton *)sender {
    PopoverView *popoverView = [PopoverView popoverView];
    [popoverView showToView:sender withActions:[self QQActions]];
}
- (IBAction)leftBarItemAction:(UIBarButtonItem *)sender {
    PopoverAction *action1 = [PopoverAction actionWithImage:[UIImage imageNamed:@"contacts_add_newmessage"] title:@"发起群聊" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action2 = [PopoverAction actionWithImage:[UIImage imageNamed:@"contacts_add_friend"] title:@"添加朋友" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action3 = [PopoverAction actionWithImage:[UIImage imageNamed:@"contacts_add_scan"] title:@"扫一扫" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action4 = [PopoverAction actionWithImage:[UIImage imageNamed:@"contacts_add_money"] title:@"收付款" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverView *popoverView = [PopoverView popoverView];
    popoverView.style = PopoverViewStyleDark;
    // 在没有系统控件的情况下调用可以使用显示在指定的点坐标的方法弹出菜单控件.
    [popoverView showToPoint:CGPointMake(20, 64) withActions:@[action1, action2, action3, action4]];
}
- (IBAction)rightButtonAction:(UIButton *)sender {
    PopoverView *popoverView = [PopoverView popoverView];
    popoverView.showShade = YES; // 显示阴影背景
    [popoverView showToView:sender withActions:[self QQActions]];
}
- (IBAction)showWithoutImage:(UIButton *)sender {
    // 不带图片
    PopoverAction *action1 = [PopoverAction actionWithTitle:@"加好友" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action2 = [PopoverAction actionWithTitle:@"扫一扫" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action3 = [PopoverAction actionWithTitle:@"发起聊天" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action4 = [PopoverAction actionWithTitle:@"发起群聊" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action5 = [PopoverAction actionWithTitle:@"查找群聊" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverAction *action6 = [PopoverAction actionWithTitle:@"我的群聊" handler:^(PopoverAction *action) {
        _noticeLabel.text = action.title;
    }];
    PopoverView *popoverView = [PopoverView popoverView];
    popoverView.style = PopoverViewStyleDark;
    popoverView.hideAfterTouchOutside = NO; // 点击外部时不允许隐藏
    [popoverView showToView:sender withActions:@[action1, action2, action3, action4, action5, action6]];
}
@end
Popover/Popover/main.m
New file
@@ -0,0 +1,16 @@
//
//  main.m
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
Popover/PopoverView/PopoverAction.h
New file
@@ -0,0 +1,27 @@
//
//  PopoverAction.h
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, PopoverViewStyle) {
    PopoverViewStyleDefault = 0, // 默认风格, 白色
    PopoverViewStyleDark, // 黑色风格
};
@interface PopoverAction : NSObject
@property (nonatomic, strong, readonly) UIImage *image; ///< 图标 (建议使用 60pix*60pix 的图片)
@property (nonatomic, copy, readonly) NSString *title; ///< 标题
@property (nonatomic, copy, readonly) void(^handler)(PopoverAction *action); ///< 选择回调, 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
+ (instancetype)actionWithTitle:(NSString *)title handler:(void (^)(PopoverAction *action))handler;
+ (instancetype)actionWithImage:(UIImage *)image title:(NSString *)title handler:(void (^)(PopoverAction *action))handler;
@end
Popover/PopoverView/PopoverAction.m
New file
@@ -0,0 +1,34 @@
//
//  PopoverAction.m
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverAction.h"
@interface PopoverAction ()
@property (nonatomic, strong, readwrite) UIImage *image; ///< 图标
@property (nonatomic, copy, readwrite) NSString *title; ///< 风格
@property (nonatomic, copy, readwrite) void(^handler)(PopoverAction *action); ///< 选择回调
@end
@implementation PopoverAction
+ (instancetype)actionWithTitle:(NSString *)title handler:(void (^)(PopoverAction *action))handler {
    return [self actionWithImage:nil title:title handler:handler];
}
+ (instancetype)actionWithImage:(UIImage *)image title:(NSString *)title handler:(void (^)(PopoverAction *action))handler {
    PopoverAction *action = [[self alloc] init];
    action.image = image;
    action.title = title ? : @"";
    action.handler = handler ? : NULL;
    return action;
}
@end
Popover/PopoverView/PopoverView.h
New file
@@ -0,0 +1,32 @@
//
//  PopoverView.h
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PopoverAction.h"
@interface PopoverView : UIView
@property (nonatomic, assign) BOOL hideAfterTouchOutside; ///< 是否开启点击外部隐藏弹窗, 默认为YES.
@property (nonatomic, assign) BOOL showShade; ///< 是否显示阴影, 如果为YES则弹窗背景为半透明的阴影层, 否则为透明, 默认为NO.
@property (nonatomic, assign) PopoverViewStyle style; ///< 弹出窗风格, 默认为 PopoverViewStyleDefault(白色).
+ (instancetype)popoverView;
/*! @brief 指向指定的View来显示弹窗
 *  @param pointView 箭头指向的View
 *  @param actions   动作对象集合<PopoverAction>
 */
- (void)showToView:(UIView *)pointView withActions:(NSArray<PopoverAction *> *)actions;
/*! @brief 指向指定的点来显示弹窗
 *  @param toPoint 箭头指向的点(这个点的坐标需按照keyWindow的坐标为参照)
 *  @param actions 动作对象集合<PopoverAction>
 */
- (void)showToPoint:(CGPoint)toPoint withActions:(NSArray<PopoverAction *> *)actions;
@end
Popover/PopoverView/PopoverView.m
New file
@@ -0,0 +1,385 @@
//
//  PopoverView.m
//  Popover
//
//  Created by lifution on 16/1/5.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverView.h"
#import "PopoverViewCell.h"
static float const kPopoverViewMargin = 8.f; ///< 边距
static float const kPopoverViewCellHeight = 40.f; ///< cell指定高度
static float const kPopoverViewArrowHeight = 13.f; ///< 箭头高度
// convert degrees to radians
float DegreesToRadians(float angle) {
    return angle*M_PI/180;
}
@interface PopoverView () <UITableViewDelegate, UITableViewDataSource>
#pragma mark - UI
@property (nonatomic, weak) UIWindow *keyWindow; ///< 当前窗口
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *shadeView; ///< 遮罩层
@property (nonatomic, weak) CAShapeLayer *borderLayer; ///< 边框Layer
#pragma mark - Data
@property (nonatomic, copy) NSArray<PopoverAction *> *actions;
@property (nonatomic, assign) CGFloat windowWidth; ///< 窗口宽度
@property (nonatomic, assign) CGFloat windowHeight; ///< 窗口高度
@property (nonatomic, assign) BOOL isUpward; ///< 箭头指向, YES为向上, 反之为向下, 默认为YES.
@end
@implementation PopoverView
#pragma mark - Lift Cycle
- (instancetype)initWithFrame:(CGRect)frame {
    if (!(self = [super initWithFrame:frame])) return nil;
    [self initialize];
    return self;
}
- (void)awakeFromNib {
    [super awakeFromNib];
    [self initialize];
}
- (void)layoutSubviews {
    [super layoutSubviews];
    _tableView.frame = CGRectMake(0, _isUpward ? kPopoverViewArrowHeight : 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - kPopoverViewArrowHeight);
}
- (void)dealloc {
    NSLog(@"PopoverView dealloced");
}
#pragma mark - Setter
- (void)setHideAfterTouchOutside:(BOOL)hideAfterTouchOutside {
    _hideAfterTouchOutside = hideAfterTouchOutside;
    _shadeView.userInteractionEnabled = _hideAfterTouchOutside;
}
- (void)setShowShade:(BOOL)showShade {
    _showShade = showShade;
    _shadeView.backgroundColor = _showShade ? [UIColor colorWithWhite:0.f alpha:0.18f] : [UIColor clearColor];
    if (_borderLayer) {
        _borderLayer.strokeColor = _showShade ? [UIColor clearColor].CGColor : _tableView.separatorColor.CGColor;
    }
}
- (void)setStyle:(PopoverViewStyle)style {
    _style = style;
    _tableView.separatorColor = [PopoverViewCell bottomLineColorForStyle:_style];
    if (_style == PopoverViewStyleDefault) {
        self.backgroundColor = [UIColor whiteColor];
    } else {
        self.backgroundColor = [UIColor colorWithRed:0.29 green:0.29 blue:0.29 alpha:1.00];
    }
}
#pragma mark - Private
/*! @brief 初始化相关 */
- (void)initialize {
    // data
    _actions = @[];
    _isUpward = YES;
    _style = PopoverViewStyleDefault;
    // current view
    self.backgroundColor = [UIColor whiteColor];
    // keyWindow
    _keyWindow = [UIApplication sharedApplication].keyWindow;
    _windowWidth = CGRectGetWidth(_keyWindow.bounds);
    _windowHeight = CGRectGetHeight(_keyWindow.bounds);
    // shadeView
    _shadeView = [[UIView alloc] initWithFrame:_keyWindow.bounds];
    [_shadeView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]];
    [self setShowShade:NO];
    // tableView
    _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    _tableView.scrollEnabled = NO;
    _tableView.showsVerticalScrollIndicator = NO;
    _tableView.backgroundColor = [UIColor clearColor];
    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    _tableView.separatorColor = [PopoverViewCell bottomLineColorForStyle:_style];
    [self addSubview:_tableView];
}
/*! @brief 显示弹窗指向某个点,  */
- (void)showToPoint:(CGPoint)toPoint {
    NSAssert(_actions.count > 0, @"actions must not be nil or empty !");
    // 截取弹窗时相关数据
    float arrowWidth = 28;
    float cornerRadius = 6.f;
    float arrowCornerRadius = 2.5f;
    float arrowBottomCornerRadius = 4.f;
    // 如果箭头指向的点过于偏左或者过于偏右则需要重新调整箭头 x 轴的坐标
    CGFloat minHorizontalEdge = kPopoverViewMargin + cornerRadius + arrowWidth/2 + 2;
    if (toPoint.x < minHorizontalEdge) {
        toPoint.x = minHorizontalEdge;
    }
    if (_windowWidth - toPoint.x < minHorizontalEdge) {
        toPoint.x = _windowWidth - minHorizontalEdge;
    }
    // 遮罩层
    _shadeView.alpha = 0.f;
    [_keyWindow addSubview:_shadeView];
    // 刷新数据以获取具体的ContentSize
    [_tableView reloadData];
    // 根据刷新后的ContentSize和箭头指向方向来设置当前视图的frame
    CGFloat currentW = [self calculateMaxWidth]; // 宽度通过计算获取最大值
    CGFloat currentH = _tableView.contentSize.height + kPopoverViewArrowHeight;
    // 限制最高高度, 免得选项太多时超出屏幕
    CGFloat maxHeight = _isUpward ? (_windowHeight - toPoint.y - kPopoverViewMargin) : (toPoint.y - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame));
    if (currentH > maxHeight) { // 如果弹窗高度大于最大高度的话则限制弹窗高度等于最大高度并允许tableView滑动.
        currentH = maxHeight;
        _tableView.scrollEnabled = YES;
        if (!_isUpward) { // 箭头指向下则移动到最后一行
            [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_actions.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
        }
    }
    CGFloat currentX = toPoint.x - currentW/2, currentY = toPoint.y;
    // x: 窗口靠左
    if (toPoint.x <= currentW/2 + kPopoverViewMargin) {
        currentX = kPopoverViewMargin;
    }
    // x: 窗口靠右
    if (_windowWidth - toPoint.x <= currentW/2 + kPopoverViewMargin) {
        currentX = _windowWidth - kPopoverViewMargin - currentW;
    }
    // y: 箭头向下
    if (!_isUpward) {
        currentY = toPoint.y - currentH;
    }
    self.frame = CGRectMake(currentX, currentY, currentW, currentH);
    // 截取箭头
    CGPoint arrowPoint = CGPointMake(toPoint.x - CGRectGetMinX(self.frame), _isUpward ? 0 : currentH); // 箭头顶点在当前视图的坐标
    CGFloat maskTop = _isUpward ? kPopoverViewArrowHeight : 0; // 顶部Y值
    CGFloat maskBottom = _isUpward ? currentH : currentH - kPopoverViewArrowHeight; // 底部Y值
    UIBezierPath *maskPath = [UIBezierPath bezierPath];
    // 左上圆角
    [maskPath moveToPoint:CGPointMake(0, cornerRadius + maskTop)];
    [maskPath addArcWithCenter:CGPointMake(cornerRadius, cornerRadius + maskTop)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(180)
                      endAngle:DegreesToRadians(270)
                     clockwise:YES];
    // 箭头向上时的箭头位置
    if (_isUpward) {
        [maskPath addLineToPoint:CGPointMake(arrowPoint.x - arrowWidth/2, kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowCornerRadius, arrowCornerRadius)
                         controlPoint:CGPointMake(arrowPoint.x - arrowWidth/2 + arrowBottomCornerRadius, kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowCornerRadius, arrowCornerRadius)
                         controlPoint:arrowPoint];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowWidth/2, kPopoverViewArrowHeight)
                         controlPoint:CGPointMake(arrowPoint.x + arrowWidth/2 - arrowBottomCornerRadius, kPopoverViewArrowHeight)];
    }
    // 右上圆角
    [maskPath addLineToPoint:CGPointMake(currentW - cornerRadius, maskTop)];
    [maskPath addArcWithCenter:CGPointMake(currentW - cornerRadius, maskTop + cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(270)
                      endAngle:DegreesToRadians(0)
                     clockwise:YES];
    // 右下圆角
    [maskPath addLineToPoint:CGPointMake(currentW, maskBottom - cornerRadius)];
    [maskPath addArcWithCenter:CGPointMake(currentW - cornerRadius, maskBottom - cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(0)
                      endAngle:DegreesToRadians(90)
                     clockwise:YES];
    // 箭头向下时的箭头位置
    if (!_isUpward) {
        [maskPath addLineToPoint:CGPointMake(arrowPoint.x + arrowWidth/2, currentH - kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x + arrowCornerRadius, currentH - arrowCornerRadius)
                         controlPoint:CGPointMake(arrowPoint.x + arrowWidth/2 - arrowBottomCornerRadius, currentH - kPopoverViewArrowHeight)];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowCornerRadius, currentH - arrowCornerRadius)
                         controlPoint:arrowPoint];
        [maskPath addQuadCurveToPoint:CGPointMake(arrowPoint.x - arrowWidth/2, currentH - kPopoverViewArrowHeight)
                         controlPoint:CGPointMake(arrowPoint.x - arrowWidth/2 + arrowBottomCornerRadius, currentH - kPopoverViewArrowHeight)];
    }
    // 左下圆角
    [maskPath addLineToPoint:CGPointMake(cornerRadius, maskBottom)];
    [maskPath addArcWithCenter:CGPointMake(cornerRadius, maskBottom - cornerRadius)
                        radius:cornerRadius
                    startAngle:DegreesToRadians(90)
                      endAngle:DegreesToRadians(180)
                     clockwise:YES];
    [maskPath closePath];
    // 截取圆角和箭头
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;
    maskLayer.path = maskPath.CGPath;
    self.layer.mask = maskLayer;
    // 边框 (只有在不显示半透明阴影层时才设置边框线条)
    if (!_showShade) {
        CAShapeLayer *borderLayer = [CAShapeLayer layer];
        borderLayer.frame = self.bounds;
        borderLayer.path = maskPath.CGPath;
        borderLayer.lineWidth = 1;
        borderLayer.fillColor = [UIColor clearColor].CGColor;
        borderLayer.strokeColor = _tableView.separatorColor.CGColor;
        [self.layer addSublayer:borderLayer];
        _borderLayer = borderLayer;
    }
    [_keyWindow addSubview:self];
    // 弹出动画
    CGRect oldFrame = self.frame;
    self.layer.anchorPoint = CGPointMake(arrowPoint.x/currentW, _isUpward ? 0.f : 1.f);
    self.frame = oldFrame;
    self.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
    [UIView animateWithDuration:0.25f animations:^{
        self.transform = CGAffineTransformIdentity;
        _shadeView.alpha = 1.f;
    }];
}
/*! @brief 计算最大宽度 */
- (CGFloat)calculateMaxWidth {
    CGFloat maxWidth = 0.f, titleLeftEdge = 0.f, imageWidth = 0.f, imageMaxHeight = kPopoverViewCellHeight - PopoverViewCellVerticalMargin*2;
    CGSize imageSize = CGSizeZero;
    UIFont *titleFont = [PopoverViewCell titleFont];
    for (PopoverAction *action in _actions) {
        imageWidth = 0.f;
        titleLeftEdge = 0.f;
        if (action.image) { // 存在图片则根据图片size和图片最大高度来重新计算图片宽度
            titleLeftEdge = PopoverViewCellTitleLeftEdge; // 有图片时标题才有左边的边距
            imageSize = action.image.size;
            if (imageSize.height > imageMaxHeight) {
                imageWidth = imageMaxHeight*imageSize.width/imageSize.height;
            } else {
                imageWidth = imageSize.width;
            }
        }
        CGFloat titleWidth;
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) { // iOS7及往后版本
            titleWidth = [action.title sizeWithAttributes:@{NSFontAttributeName : titleFont}].width;
        } else { // iOS6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
            titleWidth = [action.title sizeWithFont:titleFont].width;
#pragma GCC diagnostic pop
        }
        CGFloat contentWidth = PopoverViewCellHorizontalMargin*2 + imageWidth + titleLeftEdge + titleWidth;
        if (contentWidth > maxWidth) {
            maxWidth = ceil(contentWidth); // 获取最大宽度时需使用进一取法, 否则Cell中没有图片时会可能导致标题显示不完整.
        }
    }
    // 如果最大宽度大于(窗口宽度 - kPopoverViewMargin*2)则限制最大宽度等于(窗口宽度 - kPopoverViewMargin*2)
    if (maxWidth > CGRectGetWidth(_keyWindow.bounds) - kPopoverViewMargin*2) {
        maxWidth = CGRectGetWidth(_keyWindow.bounds) - kPopoverViewMargin*2;
    }
    return maxWidth;
}
/*! @brief 点击外部隐藏弹窗 */
- (void)hide {
    [UIView animateWithDuration:0.25f animations:^{
        self.alpha = 0.f;
        _shadeView.alpha = 0.f;
        self.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
    } completion:^(BOOL finished) {
        [_shadeView removeFromSuperview];
        [self removeFromSuperview];
    }];
}
#pragma mark - Public
+ (instancetype)popoverView {
    return [[self alloc] init];
}
/*! @brief 指向指定的View来显示弹窗 */
- (void)showToView:(UIView *)pointView withActions:(NSArray<PopoverAction *> *)actions {
    // 判断 pointView 是偏上还是偏下
    CGRect pointViewRect = [pointView.superview convertRect:pointView.frame toView:_keyWindow];
    CGFloat pointViewUpLength = CGRectGetMinY(pointViewRect);
    CGFloat pointViewDownLength = _windowHeight - CGRectGetMaxY(pointViewRect);
    // 弹窗箭头指向的点
    CGPoint toPoint = CGPointMake(CGRectGetMidX(pointViewRect), 0);
    // 弹窗在 pointView 顶部
    if (pointViewUpLength > pointViewDownLength) {
        toPoint.y = pointViewUpLength - 5;
    }
    // 弹窗在 pointView 底部
    else {
        toPoint.y = CGRectGetMaxY(pointViewRect) + 5;
    }
    // 箭头指向方向
    _isUpward = pointViewUpLength <= pointViewDownLength;
    _actions = [actions copy];
    [self showToPoint:toPoint];
}
/*! @brief 指向指定的点来显示弹窗 */
- (void)showToPoint:(CGPoint)toPoint withActions:(NSArray<PopoverAction *> *)actions {
    _actions = [actions copy];
    // 计算箭头指向方向
    _isUpward = toPoint.y <= _windowHeight - toPoint.y;
    [self showToPoint:toPoint];
}
#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _actions.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return kPopoverViewCellHeight;
}
static NSString *kPopoverCellIdentifier = @"kPopoverCellIdentifier";
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    PopoverViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPopoverCellIdentifier];
    if (!cell) {
        cell = [[PopoverViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kPopoverCellIdentifier];
    }
    [cell setAction:_actions[indexPath.row]];
    [cell showBottomLine: indexPath.row < _actions.count - 1];
    cell.style = _style;
    return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [UIView animateWithDuration:0.25f animations:^{
        self.alpha = 0.f;
        _shadeView.alpha = 0.f;
    } completion:^(BOOL finished) {
        PopoverAction *action = _actions[indexPath.row];
        action.handler ? action.handler(action) : NULL;
        _actions = nil;
        [_shadeView removeFromSuperview];
        [self removeFromSuperview];
    }];
}
@end
Popover/PopoverView/PopoverViewCell.h
New file
@@ -0,0 +1,34 @@
//
//  PopoverViewCell.h
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PopoverAction.h"
UIKIT_EXTERN float const PopoverViewCellHorizontalMargin; ///< 水平间距边距
UIKIT_EXTERN float const PopoverViewCellVerticalMargin; ///< 垂直边距
UIKIT_EXTERN float const PopoverViewCellTitleLeftEdge; ///< 标题左边边距
@class PopoverAction;
@interface PopoverViewCell : UITableViewCell
@property (nonatomic, assign) PopoverViewStyle style;
/*! @brief 标题字体
 */
+ (UIFont *)titleFont;
/*! @brief 底部线条颜色
 */
+ (UIColor *)bottomLineColorForStyle:(PopoverViewStyle)style;
- (void)setAction:(PopoverAction *)action;
- (void)showBottomLine:(BOOL)show;
@end
Popover/PopoverView/PopoverViewCell.m
New file
@@ -0,0 +1,106 @@
//
//  PopoverViewCell.m
//  Popover
//
//  Created by StevenLee on 2016/12/10.
//  Copyright © 2016年 lifution. All rights reserved.
//
#import "PopoverViewCell.h"
// extern
float const PopoverViewCellHorizontalMargin = 15.f; ///< 水平边距
float const PopoverViewCellVerticalMargin = 3.f; ///< 垂直边距
float const PopoverViewCellTitleLeftEdge = 8.f; ///< 标题左边边距
@interface PopoverViewCell ()
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, weak) UIView *bottomLine;
@end
@implementation PopoverViewCell
#pragma mark - Life Cycle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;
    self.backgroundColor = [UIColor clearColor];
    self.contentView.backgroundColor = self.backgroundColor;
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    // initialize
    [self initialize];
    return self;
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
    [super setHighlighted:highlighted animated:animated];
    if (highlighted) {
        self.backgroundColor = _style == PopoverViewStyleDefault ? [UIColor colorWithRed:0.90 green:0.90 blue:0.90 alpha:1.00] : [UIColor colorWithRed:0.23 green:0.23 blue:0.23 alpha:1.00];
    } else {
        [UIView animateWithDuration:0.3f animations:^{
            self.backgroundColor = [UIColor clearColor];
        }];
    }
}
#pragma mark - Setter
- (void)setStyle:(PopoverViewStyle)style {
    _style = style;
    _bottomLine.backgroundColor = [self.class bottomLineColorForStyle:style];
    if (_style == PopoverViewStyleDefault) {
        [_button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
    } else {
        [_button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
    }
}
#pragma mark - Private
// 初始化
- (void)initialize {
    // UI
    _button = [UIButton buttonWithType:UIButtonTypeCustom];
    _button.userInteractionEnabled = NO; // has no use for UserInteraction.
    _button.translatesAutoresizingMaskIntoConstraints = NO;
    _button.titleLabel.font = [self.class titleFont];
    _button.backgroundColor = self.contentView.backgroundColor;
    _button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
    [_button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
    [self.contentView addSubview:_button];
    // Constraint
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[_button]-margin-|" options:kNilOptions metrics:@{@"margin" : @(PopoverViewCellHorizontalMargin)} views:NSDictionaryOfVariableBindings(_button)]];
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-margin-[_button]-margin-|" options:kNilOptions metrics:@{@"margin" : @(PopoverViewCellVerticalMargin)} views:NSDictionaryOfVariableBindings(_button)]];
    // 底部线条
    UIView *bottomLine = [[UIView alloc] init];
    bottomLine.backgroundColor = [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:1.00];
    bottomLine.translatesAutoresizingMaskIntoConstraints = NO;
    [self.contentView addSubview:bottomLine];
    _bottomLine = bottomLine;
    // Constraint
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[bottomLine]|" options:kNilOptions metrics:nil views:NSDictionaryOfVariableBindings(bottomLine)]];
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomLine(lineHeight)]|" options:kNilOptions metrics:@{@"lineHeight" : @(1/[UIScreen mainScreen].scale)} views:NSDictionaryOfVariableBindings(bottomLine)]];
}
#pragma mark - Public
/*! @brief 标题字体 */
+ (UIFont *)titleFont {
    return [UIFont systemFontOfSize:15.f];
}
/*! @brief 底部线条颜色 */
+ (UIColor *)bottomLineColorForStyle:(PopoverViewStyle)style {
    return style == PopoverViewStyleDefault ? [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:1.00] : [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1.00];
}
- (void)setAction:(PopoverAction *)action {
    [_button setImage:action.image forState:UIControlStateNormal];
    [_button setTitle:action.title forState:UIControlStateNormal];
    _button.titleEdgeInsets = action.image ? UIEdgeInsetsMake(0, PopoverViewCellTitleLeftEdge, 0, -PopoverViewCellTitleLeftEdge) : UIEdgeInsetsZero;
}
- (void)showBottomLine:(BOOL)show {
    _bottomLine.hidden = !show;
}
@end
Popover/README.md
New file
@@ -0,0 +1,62 @@
# Popover
###一款优雅好用的类似QQ和微信消息页面的右上角微型菜单弹窗, 最低支持iOS6<p>
该弹窗控件有白色和黑色这两种风格, 使用方法也非常简单, 和系统的UIAlertController差不多的使用方法, 你只需要设置好对应的action和设定好弹窗箭头要指向的点(CGPoint)或者要指向的控件即可, 该弹窗控件会自动计算箭头指向和弹出位置<p>
所有效果如下图:<p>
![Alt text][image-5]<p>
该弹窗有两种风格:<p>
白色风格: `PopoverViewStyleDefault` (默认为此风格)<p>
![Alt text][image-1]<p>
黑色风格: `PopoverViewStyleDark`<p>
![Alt text][image-2]<p>
可以设置图片也可以不设置图片:
```objc
- (IBAction)showWithoutImage:(UIButton *)sender {
    PopoverAction *action1 = [PopoverAction actionWithTitle:@"Title" handler:^(PopoverAction *action) {
        // 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
    }];
    ...
    PopoverView *popoverView = [PopoverView popoverView];
    popoverView.style = PopoverViewStyleDark;
    [popoverView showToView:sender withActions:@[action1, ...]];
}
```
![Alt text][image-4]<p>
也可以设置在弹出窗口时显示背景阴影层:
```objc
- (IBAction)rightButtonAction:(UIButton *)sender {
    PopoverView *popoverView = [PopoverView popoverView];
    popoverView.showShade = YES; // 显示阴影背景
    [popoverView showToView:sender withActions:@[...]];
}
```
![Alt text][image-3]<p>
使用方法: (将PopoverView文件夹拖到你的项目中然后 `#import "PopoverView.h"` )
```objc
// 附带左边图标的
PopoverAction *action1 = [PopoverAction actionWithImage:Image title:@"Title" handler:^(PopoverAction *action) {
    // 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
}];
// 纯标题的
PopoverAction *action1 = [PopoverAction actionWithTitle:@"Title" handler:^(PopoverAction *action) {
    // 该Block不会导致内存泄露, Block内代码无需刻意去设置弱引用.
}];
...
PopoverView *popoverView = [PopoverView popoverView];
//popoverView.showShade = YES; // 显示阴影背景
//popoverView.style = PopoverViewStyleDark; // 设置为黑色风格
//popoverView.hideAfterTouchOutside = NO; // 点击外部时不允许隐藏
// 有两种显示方法
// 1. 显示在指定的控件
[popoverView showToView:sender withActions:@[action1, ...]];
// 2. 显示在指定的点(CGPoint), 该点的坐标是相对KeyWidnow的坐标.
[popoverView showToPoint:CGPointMake(20, 64) withActions:@[action1, ...]];
```
## LICENSE
PopoverView is available under the MIT license. See the LICENSE file for more info.
[image-1]:http://oeysrv69b.bkt.clouddn.com/1.png
[image-2]:http://oeysrv69b.bkt.clouddn.com/2.png
[image-3]:http://oeysrv69b.bkt.clouddn.com/5.png
[image-4]:http://oeysrv69b.bkt.clouddn.com/4.png
[image-5]:http://oeysrv69b.bkt.clouddn.com/Popover.gif
Popover/???.png