├── .gitattributes
├── .gitignore
├── README.md
├── _config.yml
├── android
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── toast
│ ├── RCTToastPackage.java
│ └── Toast.java
├── index.js
├── ios
├── RNToastNative.m
├── RNToastNative.podspec
├── RNToastNative.xcodeproj
│ └── project.pbxproj
├── UIView+Toast.h
└── UIView+Toast.m
├── package.json
└── test.gif
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # OSX
3 | #
4 | .DS_Store
5 |
6 | # node.js
7 | #
8 | node_modules/
9 | npm-debug.log
10 | yarn-error.log
11 |
12 |
13 | # Xcode
14 | #
15 | build/
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 | xcuserdata
25 | *.xccheckout
26 | *.moved-aside
27 | DerivedData
28 | *.hmap
29 | *.ipa
30 | *.xcuserstate
31 | project.xcworkspace
32 |
33 |
34 | # Android/IntelliJ
35 | #
36 | build/
37 | .idea
38 | .gradle
39 | local.properties
40 | *.iml
41 |
42 | # BUCK
43 | buck-out/
44 | \.buckd/
45 | *.keystore
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://stackshare.io/onemolegames/onemolegames)
2 |
3 | # react-native-toast-native
4 | React Native Toast is a toast component for both Android and iOS. it uses [scalessec/Toast](https://github.com/scalessec/Toast) for iOS;
5 |
6 |
7 | ## Demo:
8 | 
9 |
10 | ## Getting started
11 |
12 | `$ npm install react-native-toast-native --save`
13 |
14 | ### Mostly automatic installation
15 |
16 | `$ react-native link react-native-toast-native`
17 |
18 | ### Manual installation
19 |
20 |
21 | #### iOS (CocoaPods)
22 |
23 | Add the following to your podfile:
24 | ```
25 | pod 'RNToastNative', :path => '../node_modules/react-native-toast-native/ios`
26 | ```
27 |
28 | #### iOS
29 |
30 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
31 | 2. Go to `node_modules` ➜ `react-native-toast-native` and add `RNToastNative.xcodeproj`
32 | 3. In XCode, in the project navigator, select your project. Add `libRNToastNative.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
33 | 4. Run your project (`Cmd+R`)
34 |
35 | #### Android
36 |
37 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java`
38 | - Add `import com.toast.RCTToastPackage;` to the imports at the top of the file
39 | - Add `new RCTToastPackage()` to the list returned by the `getPackages()` method
40 | 2. Append the following lines to `android/settings.gradle`:
41 | ```
42 | include ':react-native-toast-native'
43 | project(':react-native-toast-native').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-toast-native/android')
44 | ```
45 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
46 | ```
47 | compile project(':react-native-toast-native')
48 | ```
49 |
50 | ## Usage
51 |
52 | It's just the same as [ToastAndroid](http://facebook.github.io/react-native/docs/toastandroid.html)
53 |
54 | ```javascript
55 | import Toast from 'react-native-toast-native';
56 |
57 | Toast.show(); // Default toast message is shown.
58 | Toast.show('This is a toast.'); // Specific message is shown with default duration("SHORT") and poistion("TOP") and styles.
59 | Toast.show('This is a long toast.',Toast.LONG); //Specific message and duration are shown with default position and styles.
60 | ```
61 | It is higly customasible. Just provide a style object as a parameter.
62 | example:
63 | ```javascript
64 | import Toast from 'react-native-toast-native';
65 | const styles={
66 | width,
67 | height,
68 | backgroundColor,
69 | color,
70 | borderWidth,
71 | borderColor,
72 | borderRadius
73 | }
74 |
75 | Toast.show('This is a long toast.',Toast.SHORT,Toast.TOP,styles);
76 | // Customizable toast message is shown with specific message,duration and position.
77 | ```
78 |
79 |
80 | ## Options
81 | You can style the toast with below options;
82 | Android:
83 | ```javascript
84 | {
85 | width,
86 | height,
87 | backgroundColor,
88 | color,
89 | borderWidth,
90 | paddingLeft,
91 | paddingRight,
92 | paddingBottom,
93 | paddingTop,
94 | fontSize,
95 | lineHeight,
96 | xOffset,
97 | yOffset,
98 | letterSpacing,
99 | fontWeight
100 | }
101 | ```
102 | Ios:
103 | ```javascript
104 | {
105 | width,
106 | height,
107 | backgroundColor,
108 | color,
109 | borderWidth,
110 | borderColor,
111 | borderRadius
112 | }
113 |
114 | ```
115 |
116 |
117 | if you want to make a customizable toast,you add an object like above to `show` and `showGravity`
118 |
119 | #### Example usage:
120 |
121 | ```javascript
122 | import Toast from 'react-native-toast-native';
123 | import {Platform} from 'react-native';
124 | const style={
125 | backgroundColor: "#4ADDFB",
126 | width: 300,
127 | height: Platform.OS === ("ios") ? 50 : 100,
128 | color: "#ffffff",
129 | fontSize: 15,
130 | lineHeight: 2,
131 | lines: 4,
132 | borderRadius: 15,
133 | fontWeight: "bold",
134 | yOffset: 40
135 | };
136 | Toast.show(message, Toast.SHORT, Toast.TOP,style);
137 |
138 |
139 | ```
140 |
141 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.2'
9 | }
10 | }
11 |
12 | apply plugin: 'com.android.library'
13 |
14 | android {
15 | compileSdkVersion 23
16 | buildToolsVersion "23.0.1"
17 |
18 | defaultConfig {
19 | minSdkVersion 16
20 | targetSdkVersion 22
21 | versionCode 1
22 | versionName "1.0"
23 | }
24 | lintOptions {
25 | abortOnError false
26 | }
27 | }
28 |
29 | repositories {
30 | mavenCentral()
31 | }
32 |
33 | dependencies {
34 | compile 'com.facebook.react:react-native:+'
35 | }
36 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/src/main/java/com/toast/RCTToastPackage.java:
--------------------------------------------------------------------------------
1 | package com.toast;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import com.facebook.react.ReactPackage;
8 | import com.facebook.react.bridge.JavaScriptModule;
9 | import com.facebook.react.bridge.NativeModule;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.uimanager.ViewManager;
12 |
13 | public class RCTToastPackage implements ReactPackage {
14 | @Override
15 | public List createNativeModules(ReactApplicationContext reactContext) {
16 | return Arrays.asList(
17 | new Toast(reactContext)
18 | );
19 | }
20 |
21 | @Override
22 | public List createViewManagers(ReactApplicationContext reactContext) {
23 | return Arrays.asList();
24 | }
25 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/toast/Toast.java:
--------------------------------------------------------------------------------
1 | package com.toast;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.Typeface;
6 | import android.graphics.drawable.GradientDrawable;
7 | import android.text.Layout;
8 | import android.view.Gravity;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.widget.LinearLayout;
12 | import android.widget.TextView;
13 |
14 | import com.facebook.common.logging.FLog;
15 | import com.facebook.react.bridge.*;
16 |
17 | import java.util.HashMap;
18 | import java.util.Map;
19 | import java.util.Objects;
20 |
21 | public class Toast extends ReactContextBaseJavaModule implements LifecycleEventListener {
22 | private static final String DURATION_SHORT_KEY = "SHORT";
23 | private static final String DURATION_LONG_KEY = "LONG";
24 |
25 | private static final String POSITION_TOP_KEY = "TOP";
26 | private static final String POSITION_CENTER_KEY = "CENTER";
27 | private static final String POSITION_BOTTOM_KEY = "BOTTOM";
28 |
29 | private android.widget.Toast mostRecentToast;
30 |
31 | // note that webView.isPaused() is not Xwalk compatible, so tracking it poor-man style
32 | private boolean isPaused;
33 |
34 | public Toast(ReactApplicationContext reactContext) {
35 | super(reactContext);
36 | }
37 |
38 | @Override
39 | public String getName() {
40 | return "RCTToast";
41 | }
42 |
43 | @ReactMethod
44 | public void show(final String message, final int duration, final int position, ReadableMap styles) throws Exception {
45 |
46 | if (this.isPaused) {
47 | return;
48 | }
49 | final String backgroundColor = styles.hasKey("backgroundColor") ? styles.getString("backgroundColor") : "#000000";
50 | final String color = styles.hasKey("color") ? styles.getString("color") : "#ffffff";
51 | final int width = styles.hasKey("width") ? styles.getInt("width") : 100;
52 | final int height = styles.hasKey("height") ? styles.getInt("height") : 200;
53 | final int paddingLeft = styles.hasKey("paddingLeft") ? styles.getInt("paddingLeft") : 0;
54 | final int paddingRight = styles.hasKey("paddingRight") ? styles.getInt("paddingRight") : 0;
55 | final int paddingTop = styles.hasKey("paddingTop") ? styles.getInt("paddingTop") : 0;
56 | final int paddingBottom = styles.hasKey("paddingBottom") ? styles.getInt("paddingTop") : 0;
57 | final int fontSize = styles.hasKey("fontSize") ? styles.getInt("fontSize") : 12;
58 | final int lineHeight = styles.hasKey("lineHeight") ? styles.getInt("lineHeight") : 10;
59 | final int cornerRadius = styles.hasKey("borderRadius") ? styles.getInt("borderRadius") : 5;
60 | final int lines = styles.hasKey("lines") ? styles.getInt("lines") : 3;
61 | final int borderWidth = styles.hasKey("borderWidth") ? styles.getInt("borderWidth") : 2;
62 | final int xOffset = styles.hasKey("xOffset") ? styles.getInt("xOffset") : 0;
63 | final int yOffset = styles.hasKey("yOffset") ? styles.getInt("yOffset") : 0;
64 | final float letterSpacing = styles.hasKey("letterSpacing") ? (float) styles.getDouble("letterSpacing") : 0;
65 | final String fontWeight = styles.hasKey("fontWeight") ? styles.getString("fontWeight") : "default";
66 | UiThreadUtil.runOnUiThread(new Runnable() {
67 | public void run() {
68 | android.widget.Toast toast = android.widget.Toast.makeText(
69 | getReactApplicationContext(),
70 | message,
71 | duration);
72 | View view = toast.getView();
73 | TextView text = (TextView) view.findViewById(android.R.id.message);
74 | GradientDrawable gd = new GradientDrawable();
75 | gd.setStroke(borderWidth, Color.parseColor(backgroundColor));
76 | gd.setColor(Color.parseColor(backgroundColor));
77 | gd.setCornerRadius(cornerRadius);
78 | gd.setSize(width, height);
79 | view.setBackground(gd);
80 | try{
81 | text.setTextColor(Color.parseColor(color));
82 | text.setTextSize(fontSize);
83 | text.setLines(lines);
84 | text.setMaxLines(lines);
85 | text.setHeight(lineHeight);
86 | text.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
87 | text.setTypeface(Typeface.SANS_SERIF);
88 | if(fontWeight.equals("bold")){
89 | text.setTypeface(Typeface.DEFAULT_BOLD);
90 | }else{
91 | text.setTypeface(Typeface.DEFAULT);
92 | }
93 | text.setLetterSpacing(letterSpacing);
94 | } catch (NoSuchMethodError e) {
95 | // ignore
96 | }
97 | toast.setView(view);
98 | toast.setGravity(position, xOffset, yOffset);
99 | toast.show();
100 | mostRecentToast = toast;
101 | }
102 | });
103 | }
104 |
105 | @ReactMethod
106 | public void hide() throws Exception {
107 | if (mostRecentToast != null) {
108 | mostRecentToast.cancel();
109 | }
110 | }
111 |
112 | @Override
113 | public Map getConstants() {
114 | final Map constants = new HashMap<>();
115 | constants.put(DURATION_SHORT_KEY, android.widget.Toast.LENGTH_SHORT);
116 | constants.put(DURATION_LONG_KEY, android.widget.Toast.LENGTH_LONG);
117 | constants.put(POSITION_TOP_KEY, Gravity.TOP);
118 | constants.put(POSITION_CENTER_KEY, Gravity.CENTER);
119 | constants.put(POSITION_BOTTOM_KEY, Gravity.BOTTOM);
120 | return constants;
121 | }
122 |
123 | @Override
124 | public void initialize() {
125 | getReactApplicationContext().addLifecycleEventListener(this);
126 | }
127 |
128 | @Override
129 | public void onHostPause() {
130 | if (mostRecentToast != null) {
131 | mostRecentToast.cancel();
132 | }
133 | this.isPaused = true;
134 | }
135 |
136 | @Override
137 | public void onHostResume() {
138 | this.isPaused = false;
139 | }
140 |
141 | @Override
142 | public void onHostDestroy() {
143 | this.isPaused = true;
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import {NativeModules, ToastAndroid, Platform} from "react-native";
2 |
3 | var RCTToastNative = Platform.OS === 'android' ? NativeModules.Toast : NativeModules.RNToastNative;
4 |
5 | var ToastNative = {
6 | //Toast duration constants
7 | SHORT: RCTToastNative.SHORT,
8 | LONG: RCTToastNative.LONG,
9 |
10 | // Toast gravity constants
11 | TOP: RCTToastNative.TOP,
12 | BOTTOM: RCTToastNative.BOTTOM,
13 | CENTER: RCTToastNative.CENTER,
14 |
15 | show: function (message,
16 | duration,
17 | position,
18 | styles) {
19 | RCTToastNative.show(message || "This is a toast message", duration || ToastNative.SHORT, position || ToastNative.TOP, styles || {});
20 | }
21 | };
22 |
23 | export default ToastNative;
24 |
--------------------------------------------------------------------------------
/ios/RNToastNative.m:
--------------------------------------------------------------------------------
1 | //
2 | // RNToastNative
3 | //
4 | #import
5 | #import "RCTBridgeModule.h"
6 | #import "UIView+Toast.h"
7 |
8 | NSInteger const RNToastNativeBottomOffset = 40;
9 | double const RNToastNativeShortDuration = 3.0;
10 | double const RNToastNativeLongDuration = 5.0;
11 | NSInteger const RNToastNativeGravityBottom = 1;
12 | NSInteger const RNToastNativeGravityCenter = 2;
13 | NSInteger const RNToastNativeGravityTop = 3;
14 |
15 | @interface RNToastNative : NSObject
16 | @end
17 |
18 | @implementation RNToastNative {
19 | CGFloat _keyOffset;
20 | }
21 |
22 | - (instancetype)init {
23 | if (self = [super init]) {
24 | _keyOffset = 0;
25 | [[NSNotificationCenter defaultCenter] addObserver:self
26 | selector:@selector(keyboardWasShown:)
27 | name:UIKeyboardDidShowNotification
28 | object:nil];
29 | [[NSNotificationCenter defaultCenter] addObserver:self
30 | selector:@selector(keyboardWillHiden:)
31 | name:UIKeyboardWillHideNotification
32 | object:nil];
33 | }
34 | return self;
35 | }
36 |
37 | - (void)keyboardWasShown:(NSNotification *)notification {
38 |
39 | CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
40 |
41 | int height = MIN(keyboardSize.height,keyboardSize.width);
42 | int width = MAX(keyboardSize.height,keyboardSize.width);
43 |
44 | _keyOffset = height;
45 | }
46 |
47 | - (void)keyboardWillHiden:(NSNotification *)notification {
48 | _keyOffset = 0;
49 | }
50 |
51 |
52 | RCT_EXPORT_MODULE()
53 |
54 | + (BOOL)requiresMainQueueSetup {
55 | return NO;
56 | }
57 |
58 | - (NSDictionary *)constantsToExport {
59 | return @{
60 | @"SHORT": [NSNumber numberWithDouble:RNToastNativeShortDuration],
61 | @"LONG": [NSNumber numberWithDouble:RNToastNativeLongDuration],
62 | @"BOTTOM": [NSNumber numberWithInteger:RNToastNativeGravityBottom],
63 | @"CENTER": [NSNumber numberWithInteger:RNToastNativeGravityCenter],
64 | @"TOP": [NSNumber numberWithInteger:RNToastNativeGravityTop]
65 | };
66 | }
67 |
68 | RCT_EXPORT_METHOD(show:(NSString *)msg duration:(double)duration gravity:(nonnull NSNumber *)gravity customStyle:(NSDictionary *)customStyle {
69 | [self _show:msg duration:duration gravity:gravity.intValue customStyle:customStyle];
70 | });
71 |
72 | RCT_EXPORT_METHOD(showWithGravity:(NSString *)msg duration:(double)duration gravity:(nonnull NSNumber *)gravity customStyle:(NSDictionary *)customStyle {
73 | [self _show:msg duration:duration gravity:gravity.intValue customStyle:customStyle];
74 | });
75 |
76 | - (UIViewController *)visibleViewController:(UIViewController *)rootViewController
77 | {
78 | if (rootViewController.presentedViewController == nil)
79 | {
80 | return rootViewController;
81 | }
82 | if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]])
83 | {
84 | UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
85 | UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
86 |
87 | return [self visibleViewController:lastViewController];
88 | }
89 | if ([rootViewController.presentedViewController isKindOfClass:[UITabBarController class]])
90 | {
91 | UITabBarController *tabBarController = (UITabBarController *)rootViewController.presentedViewController;
92 | UIViewController *selectedViewController = tabBarController.selectedViewController;
93 |
94 | return [self visibleViewController:selectedViewController];
95 | }
96 |
97 | UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
98 |
99 | return [self visibleViewController:presentedViewController];
100 | }
101 |
102 | - (void)_show:(NSString *)msg duration:(NSTimeInterval)duration gravity:(NSInteger)gravity customStyle:(NSDictionary *)customStyle {
103 | dispatch_async(dispatch_get_main_queue(), ^{
104 | //UIView *root = [[[[[UIApplication sharedApplication] delegate] window] rootViewController] view];
105 | UIViewController *ctrl = [self visibleViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
106 | UIView *root = [ctrl view];
107 | CGRect bound = root.bounds;
108 | bound.size.height -= _keyOffset;
109 | if (bound.size.height > RNToastNativeBottomOffset*2) {
110 | bound.origin.y += RNToastNativeBottomOffset;
111 | bound.size.height -= RNToastNativeBottomOffset*2;
112 | }
113 | UIView *view = [[UIView alloc] initWithFrame:bound];
114 | view.userInteractionEnabled = NO;
115 | [root addSubview:view];
116 | UIView __weak *blockView = view;
117 | id position;
118 | if (gravity == RNToastNativeGravityTop) {
119 | position = CSToastPositionTop;
120 | } else if (gravity == RNToastNativeGravityCenter) {
121 | position = CSToastPositionCenter;
122 | } else {
123 | position = CSToastPositionBottom;
124 | }
125 | [view makeToast:msg
126 | duration:duration
127 | position:position
128 | customStyle:customStyle
129 | title:nil
130 | image:nil
131 | style:nil
132 | completion:^(BOOL didTap) {
133 | [blockView removeFromSuperview];
134 | }];
135 | });
136 | }
137 |
138 | @end
139 |
140 |
--------------------------------------------------------------------------------
/ios/RNToastNative.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "RNToastNative"
4 | s.version = "1.0.0"
5 | s.summary = "RNToastNative"
6 | s.description = <<-DESC
7 | RNToastNative
8 | DESC
9 | s.homepage = "https://github.com/onemolegames/react-native-toast-native"
10 | s.license = "MIT"
11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
12 | s.author = { "author" => "author@domain.cn" }
13 | s.platform = :ios, "7.0"
14 | s.source = { :git => "https://github.com/author/RNToastNative.git", :tag => "master" }
15 | s.source_files = "*.{h,m}"
16 | s.requires_arc = true
17 |
18 |
19 | s.dependency "React"
20 | #s.dependency "others"
21 |
22 | end
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/RNToastNative.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B3E7B58A1CC2AC0600A0062D /* RNToastNative.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNToastNative.m */; };
11 | C101C4841EF901E60051ADA6 /* UIView+Toast.m in Sources */ = {isa = PBXBuildFile; fileRef = C101C4831EF901E60051ADA6 /* UIView+Toast.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | 58B511D91A9E6C8500147676 /* CopyFiles */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = "include/$(PRODUCT_NAME)";
19 | dstSubfolderSpec = 16;
20 | files = (
21 | );
22 | runOnlyForDeploymentPostprocessing = 0;
23 | };
24 | /* End PBXCopyFilesBuildPhase section */
25 |
26 | /* Begin PBXFileReference section */
27 | 134814201AA4EA6300B7C361 /* libRNToastNative.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNToastNative.a; sourceTree = BUILT_PRODUCTS_DIR; };
28 | B3E7B5891CC2AC0600A0062D /* RNToastNative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNToastNative.m; sourceTree = ""; };
29 | C101C4821EF901E60051ADA6 /* UIView+Toast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Toast.h"; sourceTree = ""; };
30 | C101C4831EF901E60051ADA6 /* UIView+Toast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Toast.m"; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | 58B511D81A9E6C8500147676 /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | 134814211AA4EA7D00B7C361 /* Products */ = {
45 | isa = PBXGroup;
46 | children = (
47 | 134814201AA4EA6300B7C361 /* libRNToastNative.a */,
48 | );
49 | name = Products;
50 | sourceTree = "";
51 | };
52 | 58B511D21A9E6C8500147676 = {
53 | isa = PBXGroup;
54 | children = (
55 | C101C4821EF901E60051ADA6 /* UIView+Toast.h */,
56 | C101C4831EF901E60051ADA6 /* UIView+Toast.m */,
57 | B3E7B5891CC2AC0600A0062D /* RNToastNative.m */,
58 | 134814211AA4EA7D00B7C361 /* Products */,
59 | );
60 | sourceTree = "";
61 | };
62 | /* End PBXGroup section */
63 |
64 | /* Begin PBXNativeTarget section */
65 | 58B511DA1A9E6C8500147676 /* RNToastNative */ = {
66 | isa = PBXNativeTarget;
67 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNToastNative" */;
68 | buildPhases = (
69 | 58B511D71A9E6C8500147676 /* Sources */,
70 | 58B511D81A9E6C8500147676 /* Frameworks */,
71 | 58B511D91A9E6C8500147676 /* CopyFiles */,
72 | );
73 | buildRules = (
74 | );
75 | dependencies = (
76 | );
77 | name = RNToastNative;
78 | productName = RCTDataManager;
79 | productReference = 134814201AA4EA6300B7C361 /* libRNToastNative.a */;
80 | productType = "com.apple.product-type.library.static";
81 | };
82 | /* End PBXNativeTarget section */
83 |
84 | /* Begin PBXProject section */
85 | 58B511D31A9E6C8500147676 /* Project object */ = {
86 | isa = PBXProject;
87 | attributes = {
88 | LastUpgradeCheck = 0610;
89 | ORGANIZATIONNAME = Facebook;
90 | TargetAttributes = {
91 | 58B511DA1A9E6C8500147676 = {
92 | CreatedOnToolsVersion = 6.1.1;
93 | };
94 | };
95 | };
96 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNToastNative" */;
97 | compatibilityVersion = "Xcode 3.2";
98 | developmentRegion = English;
99 | hasScannedForEncodings = 0;
100 | knownRegions = (
101 | en,
102 | );
103 | mainGroup = 58B511D21A9E6C8500147676;
104 | productRefGroup = 58B511D21A9E6C8500147676;
105 | projectDirPath = "";
106 | projectRoot = "";
107 | targets = (
108 | 58B511DA1A9E6C8500147676 /* RNToastNative */,
109 | );
110 | };
111 | /* End PBXProject section */
112 |
113 | /* Begin PBXSourcesBuildPhase section */
114 | 58B511D71A9E6C8500147676 /* Sources */ = {
115 | isa = PBXSourcesBuildPhase;
116 | buildActionMask = 2147483647;
117 | files = (
118 | C101C4841EF901E60051ADA6 /* UIView+Toast.m in Sources */,
119 | B3E7B58A1CC2AC0600A0062D /* RNToastNative.m in Sources */,
120 | );
121 | runOnlyForDeploymentPostprocessing = 0;
122 | };
123 | /* End PBXSourcesBuildPhase section */
124 |
125 | /* Begin XCBuildConfiguration section */
126 | 58B511ED1A9E6C8500147676 /* Debug */ = {
127 | isa = XCBuildConfiguration;
128 | buildSettings = {
129 | ALWAYS_SEARCH_USER_PATHS = NO;
130 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
131 | CLANG_CXX_LIBRARY = "libc++";
132 | CLANG_ENABLE_MODULES = YES;
133 | CLANG_ENABLE_OBJC_ARC = YES;
134 | CLANG_WARN_BOOL_CONVERSION = YES;
135 | CLANG_WARN_CONSTANT_CONVERSION = YES;
136 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
137 | CLANG_WARN_EMPTY_BODY = YES;
138 | CLANG_WARN_ENUM_CONVERSION = YES;
139 | CLANG_WARN_INT_CONVERSION = YES;
140 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
141 | CLANG_WARN_UNREACHABLE_CODE = YES;
142 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
143 | COPY_PHASE_STRIP = NO;
144 | ENABLE_STRICT_OBJC_MSGSEND = YES;
145 | GCC_C_LANGUAGE_STANDARD = gnu99;
146 | GCC_DYNAMIC_NO_PIC = NO;
147 | GCC_OPTIMIZATION_LEVEL = 0;
148 | GCC_PREPROCESSOR_DEFINITIONS = (
149 | "DEBUG=1",
150 | "$(inherited)",
151 | );
152 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
153 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
154 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
155 | GCC_WARN_UNDECLARED_SELECTOR = YES;
156 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
157 | GCC_WARN_UNUSED_FUNCTION = YES;
158 | GCC_WARN_UNUSED_VARIABLE = YES;
159 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
160 | MTL_ENABLE_DEBUG_INFO = YES;
161 | ONLY_ACTIVE_ARCH = YES;
162 | SDKROOT = iphoneos;
163 | };
164 | name = Debug;
165 | };
166 | 58B511EE1A9E6C8500147676 /* Release */ = {
167 | isa = XCBuildConfiguration;
168 | buildSettings = {
169 | ALWAYS_SEARCH_USER_PATHS = NO;
170 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
171 | CLANG_CXX_LIBRARY = "libc++";
172 | CLANG_ENABLE_MODULES = YES;
173 | CLANG_ENABLE_OBJC_ARC = YES;
174 | CLANG_WARN_BOOL_CONVERSION = YES;
175 | CLANG_WARN_CONSTANT_CONVERSION = YES;
176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
177 | CLANG_WARN_EMPTY_BODY = YES;
178 | CLANG_WARN_ENUM_CONVERSION = YES;
179 | CLANG_WARN_INT_CONVERSION = YES;
180 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
181 | CLANG_WARN_UNREACHABLE_CODE = YES;
182 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
183 | COPY_PHASE_STRIP = YES;
184 | ENABLE_NS_ASSERTIONS = NO;
185 | ENABLE_STRICT_OBJC_MSGSEND = YES;
186 | GCC_C_LANGUAGE_STANDARD = gnu99;
187 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
188 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
189 | GCC_WARN_UNDECLARED_SELECTOR = YES;
190 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
191 | GCC_WARN_UNUSED_FUNCTION = YES;
192 | GCC_WARN_UNUSED_VARIABLE = YES;
193 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
194 | MTL_ENABLE_DEBUG_INFO = NO;
195 | SDKROOT = iphoneos;
196 | VALIDATE_PRODUCT = YES;
197 | };
198 | name = Release;
199 | };
200 | 58B511F01A9E6C8500147676 /* Debug */ = {
201 | isa = XCBuildConfiguration;
202 | buildSettings = {
203 | HEADER_SEARCH_PATHS = (
204 | "$(inherited)",
205 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
206 | "$(SRCROOT)/../../../React/**",
207 | "$(SRCROOT)/../../react-native/React/**",
208 | );
209 | LIBRARY_SEARCH_PATHS = "$(inherited)";
210 | OTHER_LDFLAGS = "-ObjC";
211 | PRODUCT_NAME = RNToastNative;
212 | SKIP_INSTALL = YES;
213 | };
214 | name = Debug;
215 | };
216 | 58B511F11A9E6C8500147676 /* Release */ = {
217 | isa = XCBuildConfiguration;
218 | buildSettings = {
219 | HEADER_SEARCH_PATHS = (
220 | "$(inherited)",
221 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
222 | "$(SRCROOT)/../../../React/**",
223 | "$(SRCROOT)/../../react-native/React/**",
224 | );
225 | LIBRARY_SEARCH_PATHS = "$(inherited)";
226 | OTHER_LDFLAGS = "-ObjC";
227 | PRODUCT_NAME = RNToastNative;
228 | SKIP_INSTALL = YES;
229 | };
230 | name = Release;
231 | };
232 | /* End XCBuildConfiguration section */
233 |
234 | /* Begin XCConfigurationList section */
235 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNToastNative" */ = {
236 | isa = XCConfigurationList;
237 | buildConfigurations = (
238 | 58B511ED1A9E6C8500147676 /* Debug */,
239 | 58B511EE1A9E6C8500147676 /* Release */,
240 | );
241 | defaultConfigurationIsVisible = 0;
242 | defaultConfigurationName = Release;
243 | };
244 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNToastNative" */ = {
245 | isa = XCConfigurationList;
246 | buildConfigurations = (
247 | 58B511F01A9E6C8500147676 /* Debug */,
248 | 58B511F11A9E6C8500147676 /* Release */,
249 | );
250 | defaultConfigurationIsVisible = 0;
251 | defaultConfigurationName = Release;
252 | };
253 | /* End XCConfigurationList section */
254 | };
255 | rootObject = 58B511D31A9E6C8500147676 /* Project object */;
256 | }
257 |
--------------------------------------------------------------------------------
/ios/UIView+Toast.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Toast.h
3 | // Toast
4 | //
5 | // Copyright (c) 2011-2015 Charles Scalesse.
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a
8 | // copy of this software and associated documentation files (the
9 | // "Software"), to deal in the Software without restriction, including
10 | // without limitation the rights to use, copy, modify, merge, publish,
11 | // distribute, sublicense, and/or sell copies of the Software, and to
12 | // permit persons to whom the Software is furnished to do so, subject to
13 | // the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included
16 | // in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | #import
27 |
28 | extern const NSString * CSToastPositionTop;
29 | extern const NSString * CSToastPositionCenter;
30 | extern const NSString * CSToastPositionBottom;
31 |
32 | @class CSToastStyle;
33 |
34 | /**
35 | Toast is an Objective-C category that adds toast notifications to the UIView
36 | object class. It is intended to be simple, lightweight, and easy to use. Most
37 | toast notifications can be triggered with a single line of code.
38 |
39 | The `makeToast:` methods create a new view and then display it as toast.
40 |
41 | The `showToast:` methods display any view as toast.
42 |
43 | */
44 | @interface UIView (Toast)
45 |
46 | /**
47 | Creates and presents a new toast view with a message and displays it with the
48 | default duration and position. Styled using the shared style.
49 |
50 | @param message The message to be displayed
51 | */
52 | - (void)makeToast:(NSString *)message;
53 |
54 | /**
55 | Creates and presents a new toast view with a message. Duration and position
56 | can be set explicitly. Styled using the shared style.
57 |
58 | @param message The message to be displayed
59 | @param duration The toast duration
60 | @param position The toast's center point. Can be one of the predefined CSToastPosition
61 | constants or a `CGPoint` wrapped in an `NSValue` object.
62 | @param customStyle The toast customizable style
63 | */
64 | - (void)makeToast:(NSString *)message
65 | duration:(NSTimeInterval)duration
66 | position:(id)position
67 | customStyle:(NSDictionary *)customStyle;
68 |
69 | /**
70 | Creates and presents a new toast view with a message. Duration, position, and
71 | style can be set explicitly.
72 |
73 | @param message The message to be displayed
74 | @param duration The toast duration
75 | @param position The toast's center point. Can be one of the predefined CSToastPosition
76 | constants or a `CGPoint` wrapped in an `NSValue` object.
77 | @param style The style. The shared style will be used when nil
78 | @param customStyle The style.The toast customizable style when not nil
79 | */
80 | - (void)makeToast:(NSString *)message
81 | duration:(NSTimeInterval)duration
82 | position:(id)position
83 | customStyle:(NSDictionary *)customStyle
84 | style:(CSToastStyle *)style;
85 |
86 | /**
87 | Creates and presents a new toast view with a message, title, and image. Duration,
88 | position, and style can be set explicitly. The completion block executes when the
89 | toast view completes. `didTap` will be `YES` if the toast view was dismissed from
90 | a tap.
91 |
92 | @param message The message to be displayed
93 | @param duration The toast duration
94 | @param position The toast's center point. Can be one of the predefined CSToastPosition
95 | constants or a `CGPoint` wrapped in an `NSValue` object.
96 | @param title The title
97 | @param image The image
98 | @param style The style. The shared style will be used when nil
99 | @param customStyle The style.The toast customizable style when not nil
100 | @param completion The completion block, executed after the toast view disappears.
101 | didTap will be `YES` if the toast view was dismissed from a tap.
102 | */
103 | - (void)makeToast:(NSString *)message
104 | duration:(NSTimeInterval)duration
105 | position:(id)position
106 | customStyle:(NSDictionary *)customStyle
107 | title:(NSString *)title
108 | image:(UIImage *)image
109 | style:(CSToastStyle *)style
110 | completion:(void(^)(BOOL didTap))completion;
111 |
112 | /**
113 | Creates a new toast view with any combination of message, title, and image.
114 | The look and feel is configured via the style. Unlike the `makeToast:` methods,
115 | this method does not present the toast view automatically. One of the showToast:
116 | methods must be used to present the resulting view.
117 |
118 | @warning if message, title, and image are all nil, this method will return nil.
119 |
120 | @param message The message to be displayed
121 | @param title The title
122 | @param image The image
123 | @param style The style. The shared style will be used when nil
124 | @param customStyle The style.The toast customizable style when not nil
125 | @return The newly created toast view
126 | */
127 | - (UIView *)toastViewForMessage:(NSString *)message
128 | customStyle:(NSDictionary *)customStyle
129 | title:(NSString *)title
130 | image:(UIImage *)image
131 | style:(CSToastStyle *)style;
132 |
133 | /**
134 | Creates and displays a new toast activity indicator view at a specified position.
135 |
136 | @warning Only one toast activity indicator view can be presented per superview. Subsequent
137 | calls to `makeToastActivity:` will be ignored until hideToastActivity is called.
138 |
139 | @warning `makeToastActivity:` works independently of the showToast: methods. Toast activity
140 | views can be presented and dismissed while toast views are being displayed. `makeToastActivity:`
141 | has no effect on the queueing behavior of the showToast: methods.
142 |
143 | @param position The toast's center point. Can be one of the predefined CSToastPosition
144 | constants or a `CGPoint` wrapped in an `NSValue` object.
145 | */
146 | - (void)makeToastActivity:(id)position;
147 |
148 | /**
149 | Dismisses the active toast activity indicator view.
150 | */
151 | - (void)hideToastActivity;
152 |
153 | /**
154 | Displays any view as toast using the default duration and position.
155 |
156 | @param toast The view to be displayed as toast
157 | */
158 | - (void)showToast:(UIView *)toast;
159 |
160 | /**
161 | Displays any view as toast at a provided position and duration. The completion block
162 | executes when the toast view completes. `didTap` will be `YES` if the toast view was
163 | dismissed from a tap.
164 |
165 | @param toast The view to be displayed as toast
166 | @param duration The notification duration
167 | @param position The toast's center point. Can be one of the predefined CSToastPosition
168 | constants or a `CGPoint` wrapped in an `NSValue` object.
169 | @param completion The completion block, executed after the toast view disappears.
170 | didTap will be `YES` if the toast view was dismissed from a tap.
171 | @param customStyle The toast customizable style.
172 | */
173 | - (void)showToast:(UIView *)toast
174 | duration:(NSTimeInterval)duration
175 | position:(id)position
176 | customStyle:(NSDictionary *)customStyle
177 | completion:(void(^)(BOOL didTap))completion;
178 |
179 | @end
180 |
181 | /**
182 | `CSToastStyle` instances define the look and feel for toast views created via the
183 | `makeToast:` methods as well for toast views created directly with
184 | `toastViewForMessage:title:image:style:`.
185 |
186 | @warning `CSToastStyle` offers relatively simple styling options for the default
187 | toast view. If you require a toast view with more complex UI, it probably makes more
188 | sense to create your own custom UIView subclass and present it with the `showToast:`
189 | methods.
190 | */
191 | @interface CSToastStyle : NSObject
192 |
193 | /**
194 | The background color. Default is `[UIColor blackColor]` at 80% opacity.
195 | */
196 | @property (strong, nonatomic) UIColor *backgroundColor;
197 |
198 | /**
199 | The title color. Default is `[UIColor whiteColor]`.
200 | */
201 | @property (strong, nonatomic) UIColor *titleColor;
202 |
203 | /**
204 | The message color. Default is `[UIColor whiteColor]`.
205 | */
206 | @property (strong, nonatomic) UIColor *messageColor;
207 |
208 | /**
209 | A percentage value from 0.0 to 1.0, representing the maximum width of the toast
210 | view relative to it's superview. Default is 0.8 (80% of the superview's width).
211 | */
212 | @property (assign, nonatomic) CGFloat maxWidthPercentage;
213 |
214 | /**
215 | A percentage value from 0.0 to 1.0, representing the maximum height of the toast
216 | view relative to it's superview. Default is 0.8 (80% of the superview's height).
217 | */
218 | @property (assign, nonatomic) CGFloat maxHeightPercentage;
219 |
220 | /**
221 | The spacing from the horizontal edge of the toast view to the content. When an image
222 | is present, this is also used as the padding between the image and the text.
223 | Default is 10.0.
224 | */
225 | @property (assign, nonatomic) CGFloat horizontalPadding;
226 |
227 | /**
228 | The spacing from the vertical edge of the toast view to the content. When a title
229 | is present, this is also used as the padding between the title and the message.
230 | Default is 10.0.
231 | */
232 | @property (assign, nonatomic) CGFloat verticalPadding;
233 |
234 | /**
235 | The corner radius. Default is 10.0.
236 | */
237 | @property (assign, nonatomic) CGFloat cornerRadius;
238 |
239 | /**
240 | The title font. Default is `[UIFont boldSystemFontOfSize:16.0]`.
241 | */
242 | @property (strong, nonatomic) UIFont *titleFont;
243 |
244 | /**
245 | The message font. Default is `[UIFont systemFontOfSize:16.0]`.
246 | */
247 | @property (strong, nonatomic) UIFont *messageFont;
248 |
249 | /**
250 | The title text alignment. Default is `NSTextAlignmentLeft`.
251 | */
252 | @property (assign, nonatomic) NSTextAlignment titleAlignment;
253 |
254 | /**
255 | The message text alignment. Default is `NSTextAlignmentLeft`.
256 | */
257 | @property (assign, nonatomic) NSTextAlignment messageAlignment;
258 |
259 | /**
260 | The maximum number of lines for the title. The default is 0 (no limit).
261 | */
262 | @property (assign, nonatomic) NSInteger titleNumberOfLines;
263 |
264 | /**
265 | The maximum number of lines for the message. The default is 0 (no limit).
266 | */
267 | @property (assign, nonatomic) NSInteger messageNumberOfLines;
268 |
269 | /**
270 | Enable or disable a shadow on the toast view. Default is `NO`.
271 | */
272 | @property (assign, nonatomic) BOOL displayShadow;
273 |
274 | /**
275 | The shadow color. Default is `[UIColor blackColor]`.
276 | */
277 | @property (strong, nonatomic) UIColor *shadowColor;
278 |
279 | /**
280 | A value from 0.0 to 1.0, representing the opacity of the shadow.
281 | Default is 0.8 (80% opacity).
282 | */
283 | @property (assign, nonatomic) CGFloat shadowOpacity;
284 |
285 | /**
286 | The shadow radius. Default is 6.0.
287 | */
288 | @property (assign, nonatomic) CGFloat shadowRadius;
289 |
290 | /**
291 | The shadow offset. The default is `CGSizeMake(4.0, 4.0)`.
292 | */
293 | @property (assign, nonatomic) CGSize shadowOffset;
294 |
295 | /**
296 | The image size. The default is `CGSizeMake(80.0, 80.0)`.
297 | */
298 | @property (assign, nonatomic) CGSize imageSize;
299 |
300 | /**
301 | The size of the toast activity view when `makeToastActivity:` is called.
302 | Default is `CGSizeMake(100.0, 100.0)`.
303 | */
304 | @property (assign, nonatomic) CGSize activitySize;
305 |
306 | /**
307 | The fade in/out animation duration. Default is 0.2.
308 | */
309 | @property (assign, nonatomic) NSTimeInterval fadeDuration;
310 |
311 | /**
312 | Creates a new instance of `CSToastStyle` with all the default values set.
313 | */
314 | - (instancetype)initWithDefaultStyle NS_DESIGNATED_INITIALIZER;
315 |
316 | /**
317 | @warning Only the designated initializer should be used to create
318 | an instance of `CSToastStyle`.
319 | */
320 | - (instancetype)init NS_UNAVAILABLE;
321 |
322 | @end
323 |
324 | /**
325 | `CSToastManager` provides general configuration options for all toast
326 | notifications. Backed by a singleton instance.
327 | */
328 | @interface CSToastManager : NSObject
329 |
330 | /**
331 | Sets the shared style on the singleton. The shared style is used whenever
332 | a `makeToast:` method (or `toastViewForMessage:title:image:style:`) is called
333 | with with a nil style. By default, this is set to `CSToastStyle`'s default
334 | style.
335 |
336 | @param sharedStyle
337 | */
338 | + (void)setSharedStyle:(CSToastStyle *)sharedStyle;
339 |
340 | /**
341 | Gets the shared style from the singlton. By default, this is
342 | `CSToastStyle`'s default style.
343 |
344 | @return the shared style
345 | */
346 | + (CSToastStyle *)sharedStyle;
347 |
348 | /**
349 | Enables or disables tap to dismiss on toast views. Default is `YES`.
350 |
351 | @param allowTapToDismiss
352 | */
353 | + (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled;
354 |
355 | /**
356 | Returns `YES` if tap to dismiss is enabled, otherwise `NO`.
357 | Default is `YES`.
358 |
359 | @return BOOL
360 | */
361 | + (BOOL)isTapToDismissEnabled;
362 |
363 | /**
364 | Enables or disables queueing behavior for toast views. When `YES`,
365 | toast views will appear one after the other. When `NO`, multiple Toast
366 | views will appear at the same time (potentially overlapping depending
367 | on their positions). This has no effect on the toast activity view,
368 | which operates independently of normal toast views. Default is `YES`.
369 |
370 | @param queueEnabled
371 | */
372 | + (void)setQueueEnabled:(BOOL)queueEnabled;
373 |
374 | /**
375 | Returns `YES` if the queue is enabled, otherwise `NO`.
376 | Default is `YES`.
377 |
378 | @return BOOL
379 | */
380 | + (BOOL)isQueueEnabled;
381 |
382 | /**
383 | Sets the default duration. Used for the `makeToast:` and
384 | `showToast:` methods that don't require an explicit duration.
385 | Default is 3.0.
386 |
387 | @param duration The toast duration
388 | */
389 | + (void)setDefaultDuration:(NSTimeInterval)duration;
390 |
391 | /**
392 | Returns the default duration. Default is 3.0.
393 |
394 | @return duration The toast duration
395 | */
396 | + (NSTimeInterval)defaultDuration;
397 |
398 | /**
399 | Sets the default position. Used for the `makeToast:` and
400 | `showToast:` methods that don't require an explicit position.
401 | Default is `CSToastPositionBottom`.
402 |
403 | @param position The default center point. Can be one of the predefined
404 | CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object.
405 | */
406 | + (void)setDefaultPosition:(id)position;
407 |
408 | /**
409 | Returns the default toast position. Default is `CSToastPositionBottom`.
410 |
411 | @return position The default center point. Will be one of the predefined
412 | CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object.
413 | */
414 | + (id)defaultPosition;
415 |
416 | @end
417 |
--------------------------------------------------------------------------------
/ios/UIView+Toast.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Toast.m
3 | // Toast
4 | //
5 | // Copyright (c) 2011-2015 Charles Scalesse.
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a
8 | // copy of this software and associated documentation files (the
9 | // "Software"), to deal in the Software without restriction, including
10 | // without limitation the rights to use, copy, modify, merge, publish,
11 | // distribute, sublicense, and/or sell copies of the Software, and to
12 | // permit persons to whom the Software is furnished to do so, subject to
13 | // the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included
16 | // in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | #import "UIView+Toast.h"
27 | #import
28 | #import
29 |
30 | NSString * CSToastPositionTop = @"CSToastPositionTop";
31 | NSString * CSToastPositionCenter = @"CSToastPositionCenter";
32 | NSString * CSToastPositionBottom = @"CSToastPositionBottom";
33 |
34 | // Keys for values associated with toast views
35 | static const NSString * CSToastTimerKey = @"CSToastTimerKey";
36 | static const NSString * CSToastDurationKey = @"CSToastDurationKey";
37 | static const NSString * CSToastPositionKey = @"CSToastPositionKey";
38 | static const NSString * CSToastCompletionKey = @"CSToastCompletionKey";
39 |
40 | // Keys for values associated with self
41 | static const NSString * CSToastActiveToastViewKey = @"CSToastActiveToastViewKey";
42 | static const NSString * CSToastActivityViewKey = @"CSToastActivityViewKey";
43 | static const NSString * CSToastQueueKey = @"CSToastQueueKey";
44 |
45 | @interface UIView (ToastPrivate)
46 |
47 | /**
48 | These private methods are being prefixed with "cs_" to reduce the likelihood of non-obvious
49 | naming conflicts with other UIView methods.
50 |
51 | @discussion Should the public API also use the cs_ prefix? Technically it should, but it
52 | results in code that is less legible. The current public method names seem unlikely to cause
53 | conflicts so I think we should favor the cleaner API for now.
54 | */
55 | - (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position;
56 | - (void)cs_hideToast:(UIView *)toast;
57 | - (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap;
58 | - (void)cs_toastTimerDidFinish:(NSTimer *)timer;
59 | - (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer;
60 | - (CGPoint)cs_centerPointForPosition:(id)position withToast:(UIView *)toast;
61 | - (NSMutableArray *)cs_toastQueue;
62 |
63 | @end
64 |
65 | @implementation UIView (Toast)
66 |
67 | #pragma mark - Make Toast Methods
68 |
69 | - (void)makeToast:(NSString *)message {
70 | [self makeToast:message duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] customStyle:nil style:nil];
71 | }
72 |
73 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position customStyle:(NSDictionary *)customStyle {
74 | [self makeToast:message duration:duration position:position customStyle:customStyle style:nil];
75 | }
76 |
77 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position customStyle:(NSDictionary *)customStyle style:(CSToastStyle *)style {
78 | UIView *toast = [self toastViewForMessage:message customStyle:customStyle title:nil image:nil style:style];
79 | [self showToast:toast duration:duration position:position customStyle:customStyle completion:nil];
80 | }
81 |
82 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position customStyle:(NSDictionary *)customStyle title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style completion:(void(^)(BOOL didTap))completion {
83 | UIView *toast = [self toastViewForMessage:message customStyle:customStyle title:title image:image style:style];
84 | [self showToast:toast duration:duration position:position customStyle:customStyle completion:completion];
85 | }
86 |
87 | #pragma mark - Show Toast Methods
88 |
89 | - (void)showToast:(UIView *)toast {
90 | [self showToast:toast duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] customStyle:nil completion:nil];
91 | }
92 |
93 | - (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position customStyle:(NSDictionary *)customStyle completion:(void(^)(BOOL didTap))completion {
94 | // sanity
95 | if (toast == nil) return;
96 |
97 | // store the completion block on the toast view
98 | objc_setAssociatedObject(toast, &CSToastCompletionKey, completion, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
99 |
100 | if ([CSToastManager isQueueEnabled] && objc_getAssociatedObject(self, &CSToastActiveToastViewKey) != nil) {
101 | // we're about to queue this toast view so we need to store the duration and position as well
102 | objc_setAssociatedObject(toast, &CSToastDurationKey, @(duration), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
103 | objc_setAssociatedObject(toast, &CSToastPositionKey, position, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
104 |
105 | // enqueue
106 | [self.cs_toastQueue addObject:toast];
107 | } else {
108 | // present
109 | [self cs_showToast:toast duration:duration position:position customStyle:customStyle];
110 | }
111 | }
112 |
113 | #pragma mark - Private Show/Hide Methods
114 |
115 | - (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position customStyle:(NSDictionary *)customStyle {
116 | toast.center = [self cs_centerPointForPosition:position withToast:toast];
117 | toast.alpha = 0.0;
118 |
119 | if ([CSToastManager isTapToDismissEnabled]) {
120 | UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cs_handleToastTapped:)];
121 | [toast addGestureRecognizer:recognizer];
122 | toast.userInteractionEnabled = YES;
123 | toast.exclusiveTouch = YES;
124 | }
125 |
126 | // set the active toast
127 | objc_setAssociatedObject(self, &CSToastActiveToastViewKey, toast, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
128 |
129 | [self addSubview:toast];
130 |
131 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
132 | delay:0.0
133 | options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction)
134 | animations:^{
135 | toast.alpha = 1.0;
136 | } completion:^(BOOL finished) {
137 | NSTimer *timer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(cs_toastTimerDidFinish:) userInfo:toast repeats:NO];
138 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
139 | objc_setAssociatedObject(toast, &CSToastTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
140 | }];
141 | }
142 |
143 | - (void)cs_hideToast:(UIView *)toast {
144 | [self cs_hideToast:toast fromTap:NO];
145 | }
146 |
147 | - (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap {
148 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
149 | delay:0.0
150 | options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
151 | animations:^{
152 | toast.alpha = 0.0;
153 | } completion:^(BOOL finished) {
154 | [toast removeFromSuperview];
155 |
156 | // clear the active toast
157 | objc_setAssociatedObject(self, &CSToastActiveToastViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
158 |
159 | // execute the completion block, if necessary
160 | void (^completion)(BOOL didTap) = objc_getAssociatedObject(toast, &CSToastCompletionKey);
161 | if (completion) {
162 | completion(fromTap);
163 | }
164 |
165 | if ([self.cs_toastQueue count] > 0) {
166 | // dequeue
167 | UIView *nextToast = [[self cs_toastQueue] firstObject];
168 | [[self cs_toastQueue] removeObjectAtIndex:0];
169 |
170 | // present the next toast
171 | NSTimeInterval duration = [objc_getAssociatedObject(nextToast, &CSToastDurationKey) doubleValue];
172 | id position = objc_getAssociatedObject(nextToast, &CSToastPositionKey);
173 | [self cs_showToast:nextToast duration:duration position:position];
174 | }
175 | }];
176 | }
177 | /*
178 | This method created because of hex color convert to UIColor type.
179 | */
180 | - (UIColor *)stringColorConvertoUIColor:(NSString *)color {
181 | unsigned int c;
182 | if ([color characterAtIndex:0] == '#') {
183 | [[NSScanner scannerWithString:[color substringFromIndex:1]] scanHexInt:&c];
184 | } else {
185 | [[NSScanner scannerWithString:color] scanHexInt:&c];
186 | }
187 | return [UIColor colorWithRed:((c & 0xff0000) >> 16)/255.0 green:((c & 0xff00) >> 8)/255.0 blue:(c & 0xff)/255.0 alpha:1.0];
188 | }
189 |
190 | #pragma mark - View Construction
191 |
192 | - (UIView *)toastViewForMessage:(NSString *)message customStyle:(NSDictionary *)customStyle title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style {
193 | // sanity
194 | if(message == nil && title == nil && image == nil && customStyle == nil) return nil;
195 |
196 | // default to the shared style
197 | if (style == nil) {
198 | style = [CSToastManager sharedStyle];
199 | }
200 |
201 | // dynamically build a toast view with any combination of message, title, & image
202 | UILabel *messageLabel = nil;
203 | UILabel *titleLabel = nil;
204 | UIImageView *imageView = nil;
205 | UIColor *textColor;
206 | struct CGColor *borderColor=nil;
207 | struct CGColor *backgroundColor=nil;
208 | float borderWidth=1.0;
209 | float borderRadius=1.0;
210 | float width=0.0;
211 | float height=0.0;
212 | UIView *wrapperView = [[UIView alloc] init];
213 | wrapperView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
214 | wrapperView.layer.cornerRadius = style.cornerRadius;
215 |
216 | if (style.displayShadow) {
217 | wrapperView.layer.shadowColor = style.shadowColor.CGColor;
218 | wrapperView.layer.shadowOpacity = style.shadowOpacity;
219 | wrapperView.layer.shadowRadius = style.shadowRadius;
220 | wrapperView.layer.shadowOffset = style.shadowOffset;
221 | }
222 |
223 | wrapperView.backgroundColor = [UIColor clearColor];
224 |
225 | if(image != nil) {
226 | imageView = [[UIImageView alloc] initWithImage:image];
227 | imageView.contentMode = UIViewContentModeScaleAspectFit;
228 | imageView.frame = CGRectMake(style.horizontalPadding, style.verticalPadding, style.imageSize.width, style.imageSize.height);
229 | }
230 |
231 | CGRect imageRect = CGRectZero;
232 |
233 | if(imageView != nil) {
234 | imageRect.origin.x = style.horizontalPadding;
235 | imageRect.origin.y = style.verticalPadding;
236 | imageRect.size.width = imageView.bounds.size.width;
237 | imageRect.size.height = imageView.bounds.size.height;
238 | }
239 |
240 | if (title != nil) {
241 | titleLabel = [[UILabel alloc] init];
242 | titleLabel.numberOfLines = style.titleNumberOfLines;
243 | titleLabel.font = style.titleFont;
244 | titleLabel.textAlignment = style.titleAlignment;
245 | titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
246 | titleLabel.textColor = style.titleColor;
247 | titleLabel.backgroundColor = [UIColor clearColor];
248 | titleLabel.alpha = 1.0;
249 | titleLabel.text = title;
250 |
251 | // size the title label according to the length of the text
252 | CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage);
253 | CGSize expectedSizeTitle = [titleLabel sizeThatFits:maxSizeTitle];
254 | // UILabel can return a size larger than the max size when the number of lines is 1
255 | expectedSizeTitle = CGSizeMake(MIN(maxSizeTitle.width, expectedSizeTitle.width), MIN(maxSizeTitle.height, expectedSizeTitle.height));
256 | titleLabel.frame = CGRectMake(0.0, 0.0, expectedSizeTitle.width, expectedSizeTitle.height);
257 | }
258 | if(customStyle && customStyle[@"color"]){
259 | textColor=[self stringColorConvertoUIColor:customStyle[@"color"]];
260 | }
261 | if(customStyle && !customStyle[@"color"]){
262 | textColor=style.messageColor;
263 | }
264 | if(customStyle && customStyle[@"borderColor"]){
265 | borderColor=[self stringColorConvertoUIColor:customStyle[@"borderColor"]].CGColor;
266 | }
267 | if(customStyle && !customStyle[@"borderColor"]){
268 | borderColor=[UIColor clearColor].CGColor;
269 | }
270 | if(customStyle && customStyle[@"borderWidth"]){
271 | borderWidth=(float)[customStyle[@"borderWidth"] floatValue];
272 | }
273 | if(customStyle && !customStyle[@"borderWidth"]){
274 | borderWidth=0;
275 | }
276 | if(customStyle && customStyle[@"borderRadius"]){
277 | borderRadius=(float)[customStyle[@"borderRadius"] floatValue];
278 | }
279 | if(customStyle && !customStyle[@"borderRadius"]){
280 | borderRadius=0;
281 | }
282 | if(customStyle && customStyle[@"backgroundColor"]){
283 | backgroundColor=[self stringColorConvertoUIColor:customStyle[@"backgroundColor"]].CGColor;
284 | }
285 | if(customStyle && !customStyle[@"backgroundColor"]){
286 | backgroundColor=style.backgroundColor.CGColor;
287 | }
288 | if(customStyle && customStyle[@"width"]){
289 | width=[customStyle[@"width"] floatValue];
290 | }
291 |
292 | if(!customStyle){
293 | textColor=style.messageColor;
294 | borderColor=[UIColor clearColor].CGColor;
295 | borderWidth=0;
296 | borderRadius=0;
297 | backgroundColor=style.backgroundColor.CGColor;
298 | }
299 | if (message != nil) {
300 | messageLabel=[[UILabel alloc] init];
301 | messageLabel.numberOfLines = style.messageNumberOfLines;
302 | messageLabel.font = style.messageFont;
303 | messageLabel.textAlignment =style.messageAlignment;
304 | messageLabel.lineBreakMode = NSLineBreakByTruncatingTail;
305 | messageLabel.textColor =textColor;
306 | messageLabel.layer.borderColor = borderColor;
307 | messageLabel.layer.borderWidth=borderWidth;
308 | messageLabel.layer.cornerRadius=borderRadius;
309 | messageLabel.layer.backgroundColor = backgroundColor;
310 | messageLabel.backgroundColor = [UIColor clearColor];
311 | messageLabel.alpha = 1.0;
312 | messageLabel.text = message;
313 |
314 | CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage);
315 | CGSize expectedSizeMessage = [messageLabel sizeThatFits:maxSizeMessage];
316 | // UILabel can return a size larger than the max size when the number of lines is 1
317 | expectedSizeMessage = CGSizeMake(MIN(maxSizeMessage.width, expectedSizeMessage.width), MIN(maxSizeMessage.height, expectedSizeMessage.height));
318 | messageLabel.frame = CGRectMake(0.0, 0.0, expectedSizeMessage.width, expectedSizeMessage.height);
319 | }
320 |
321 | CGRect titleRect = CGRectZero;
322 |
323 | if(customStyle && !customStyle[@"width"]){
324 | width=messageLabel.bounds.size.width;
325 | }
326 | if(customStyle && customStyle[@"height"]){
327 | height=[customStyle[@"height"] floatValue];
328 | }
329 | if(customStyle && !customStyle[@"height"]){
330 | height=messageLabel.bounds.size.height;
331 | }
332 | if(!customStyle){
333 | width=messageLabel.bounds.size.width;
334 | height=messageLabel.bounds.size.height;
335 | }
336 |
337 | if(titleLabel != nil) {
338 | titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding;
339 | titleRect.origin.y = style.verticalPadding;
340 | titleRect.size.width = titleLabel.bounds.size.width;
341 | titleRect.size.height = titleLabel.bounds.size.height;
342 | }
343 |
344 | CGRect messageRect = CGRectZero;
345 |
346 | if(messageLabel != nil) {
347 | messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding;
348 | messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding;
349 | messageRect.size.width = width;
350 | messageRect.size.height = height;
351 | }
352 |
353 | CGFloat longerWidth = MAX(titleRect.size.width, messageRect.size.width);
354 | CGFloat longerX = MAX(titleRect.origin.x, messageRect.origin.x);
355 |
356 | // Wrapper width uses the longerWidth or the image width, whatever is larger. Same logic applies to the wrapper height.
357 | CGFloat wrapperWidth = MAX((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding));
358 | CGFloat wrapperHeight = MAX((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0)));
359 |
360 | wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight);
361 |
362 | if(titleLabel != nil) {
363 | titleLabel.frame = titleRect;
364 | [wrapperView addSubview:titleLabel];
365 | }
366 |
367 | if(messageLabel != nil) {
368 | messageLabel.frame = messageRect;
369 | [wrapperView addSubview:messageLabel];
370 | }
371 |
372 | if(imageView != nil) {
373 | [wrapperView addSubview:imageView];
374 | }
375 |
376 | return wrapperView;
377 | }
378 |
379 | #pragma mark - Queue
380 |
381 | - (NSMutableArray *)cs_toastQueue {
382 | NSMutableArray *cs_toastQueue = objc_getAssociatedObject(self, &CSToastQueueKey);
383 | if (cs_toastQueue == nil) {
384 | cs_toastQueue = [[NSMutableArray alloc] init];
385 | objc_setAssociatedObject(self, &CSToastQueueKey, cs_toastQueue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
386 | }
387 | return cs_toastQueue;
388 | }
389 |
390 | #pragma mark - Events
391 |
392 | - (void)cs_toastTimerDidFinish:(NSTimer *)timer {
393 | [self cs_hideToast:(UIView *)timer.userInfo];
394 | }
395 |
396 | - (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer {
397 | UIView *toast = recognizer.view;
398 | NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey);
399 | [timer invalidate];
400 |
401 | [self cs_hideToast:toast fromTap:YES];
402 | }
403 |
404 | #pragma mark - Activity Methods
405 |
406 | - (void)makeToastActivity:(id)position {
407 | // sanity
408 | UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey);
409 | if (existingActivityView != nil) return;
410 |
411 | CSToastStyle *style = [CSToastManager sharedStyle];
412 |
413 | UIView *activityView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, style.activitySize.width, style.activitySize.height)];
414 | activityView.center = [self cs_centerPointForPosition:position withToast:activityView];
415 | activityView.backgroundColor = style.backgroundColor;
416 | activityView.alpha = 0.0;
417 | activityView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
418 | activityView.layer.cornerRadius = style.cornerRadius;
419 |
420 | if (style.displayShadow) {
421 | activityView.layer.shadowColor = style.shadowColor.CGColor;
422 | activityView.layer.shadowOpacity = style.shadowOpacity;
423 | activityView.layer.shadowRadius = style.shadowRadius;
424 | activityView.layer.shadowOffset = style.shadowOffset;
425 | }
426 |
427 | UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
428 | activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2);
429 | [activityView addSubview:activityIndicatorView];
430 | [activityIndicatorView startAnimating];
431 |
432 | // associate the activity view with self
433 | objc_setAssociatedObject (self, &CSToastActivityViewKey, activityView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
434 |
435 | [self addSubview:activityView];
436 |
437 | [UIView animateWithDuration:style.fadeDuration
438 | delay:0.0
439 | options:UIViewAnimationOptionCurveEaseOut
440 | animations:^{
441 | activityView.alpha = 1.0;
442 | } completion:nil];
443 | }
444 |
445 | - (void)hideToastActivity {
446 | UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey);
447 | if (existingActivityView != nil) {
448 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
449 | delay:0.0
450 | options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
451 | animations:^{
452 | existingActivityView.alpha = 0.0;
453 | } completion:^(BOOL finished) {
454 | [existingActivityView removeFromSuperview];
455 | objc_setAssociatedObject (self, &CSToastActivityViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
456 | }];
457 | }
458 | }
459 |
460 | #pragma mark - Helpers
461 |
462 | - (CGPoint)cs_centerPointForPosition:(id)point withToast:(UIView *)toast {
463 | CSToastStyle *style = [CSToastManager sharedStyle];
464 |
465 | if([point isKindOfClass:[NSString class]]) {
466 | if([point caseInsensitiveCompare:CSToastPositionTop] == NSOrderedSame) {
467 | return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + style.verticalPadding);
468 | } else if([point caseInsensitiveCompare:CSToastPositionCenter] == NSOrderedSame) {
469 | return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
470 | }
471 | } else if ([point isKindOfClass:[NSValue class]]) {
472 | return [point CGPointValue];
473 | }
474 |
475 | // default to bottom
476 | return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - style.verticalPadding);
477 | }
478 |
479 | @end
480 |
481 | @implementation CSToastStyle
482 |
483 | #pragma mark - Constructors
484 |
485 | - (instancetype)initWithDefaultStyle {
486 | self = [super init];
487 | if (self) {
488 | self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8];
489 | self.titleColor = [UIColor whiteColor];
490 | self.messageColor = [UIColor whiteColor];
491 | self.maxWidthPercentage = 0.8;
492 | self.maxHeightPercentage = 0.8;
493 | self.horizontalPadding = 10.0;
494 | self.verticalPadding = 10.0;
495 | self.cornerRadius = 10.0;
496 | self.titleFont = [UIFont boldSystemFontOfSize:16.0];
497 | self.messageFont = [UIFont systemFontOfSize:16.0];
498 | self.titleAlignment = NSTextAlignmentCenter;
499 | self.messageAlignment = NSTextAlignmentCenter;
500 | self.titleNumberOfLines = 0;
501 | self.messageNumberOfLines = 0;
502 | self.displayShadow = NO;
503 | self.shadowOpacity = 0.8;
504 | self.shadowRadius = 6.0;
505 | self.shadowOffset = CGSizeMake(4.0, 4.0);
506 | self.imageSize = CGSizeMake(80.0, 80.0);
507 | self.activitySize = CGSizeMake(100.0, 100.0);
508 | self.fadeDuration = 0.2;
509 | }
510 | return self;
511 | }
512 |
513 | - (void)setMaxWidthPercentage:(CGFloat)maxWidthPercentage {
514 | _maxWidthPercentage = MAX(MIN(maxWidthPercentage, 1.0), 0.0);
515 | }
516 |
517 | - (void)setMaxHeightPercentage:(CGFloat)maxHeightPercentage {
518 | _maxHeightPercentage = MAX(MIN(maxHeightPercentage, 1.0), 0.0);
519 | }
520 |
521 | - (instancetype)init NS_UNAVAILABLE {
522 | return nil;
523 | }
524 |
525 | @end
526 |
527 | @interface CSToastManager ()
528 |
529 | @property (strong, nonatomic) CSToastStyle *sharedStyle;
530 | @property (assign, nonatomic, getter=isTapToDismissEnabled) BOOL tapToDismissEnabled;
531 | @property (assign, nonatomic, getter=isQueueEnabled) BOOL queueEnabled;
532 | @property (assign, nonatomic) NSTimeInterval defaultDuration;
533 | @property (strong, nonatomic) id defaultPosition;
534 |
535 | @end
536 |
537 | @implementation CSToastManager
538 |
539 | #pragma mark - Constructors
540 |
541 | + (instancetype)sharedManager {
542 | static CSToastManager *_sharedManager = nil;
543 | static dispatch_once_t oncePredicate;
544 | dispatch_once(&oncePredicate, ^{
545 | _sharedManager = [[self alloc] init];
546 | });
547 |
548 | return _sharedManager;
549 | }
550 |
551 | - (instancetype)init {
552 | self = [super init];
553 | if (self) {
554 | self.sharedStyle = [[CSToastStyle alloc] initWithDefaultStyle];
555 | self.tapToDismissEnabled = YES;
556 | self.queueEnabled = YES;
557 | self.defaultDuration = 3.0;
558 | self.defaultPosition = CSToastPositionBottom;
559 | }
560 | return self;
561 | }
562 |
563 | #pragma mark - Singleton Methods
564 |
565 | + (void)setSharedStyle:(CSToastStyle *)sharedStyle {
566 | [[self sharedManager] setSharedStyle:sharedStyle];
567 | }
568 |
569 | + (CSToastStyle *)sharedStyle {
570 | return [[self sharedManager] sharedStyle];
571 | }
572 |
573 | + (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled {
574 | [[self sharedManager] setTapToDismissEnabled:tapToDismissEnabled];
575 | }
576 |
577 | + (BOOL)isTapToDismissEnabled {
578 | return [[self sharedManager] isTapToDismissEnabled];
579 | }
580 |
581 | + (void)setQueueEnabled:(BOOL)queueEnabled {
582 | [[self sharedManager] setQueueEnabled:queueEnabled];
583 | }
584 |
585 | + (BOOL)isQueueEnabled {
586 | return [[self sharedManager] isQueueEnabled];
587 | }
588 |
589 | + (void)setDefaultDuration:(NSTimeInterval)duration {
590 | [[self sharedManager] setDefaultDuration:duration];
591 | }
592 |
593 | + (NSTimeInterval)defaultDuration {
594 | return [[self sharedManager] defaultDuration];
595 | }
596 |
597 | + (void)setDefaultPosition:(id)position {
598 | if ([position isKindOfClass:[NSString class]] || [position isKindOfClass:[NSValue class]]) {
599 | [[self sharedManager] setDefaultPosition:position];
600 | }
601 | }
602 |
603 | + (id)defaultPosition {
604 | return [[self sharedManager] defaultPosition];
605 | }
606 |
607 | @end
608 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "name": "react-native-toast-native",
4 | "version": "1.2.1",
5 | "description": "Native toast for react-native. In Android it's just native toast, in iOS it's https://github.com/scalessec/Toast",
6 | "main": "index.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [
11 | "react-native",
12 | "native",
13 | "toast"
14 | ],
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/onemolegames/react-native-toast-native"
18 | },
19 | "author": "yasemincidem",
20 | "license": "MIT",
21 | "peerDependencies": {
22 | "react": "*",
23 | "react-native": "*"
24 | }
25 | }
--------------------------------------------------------------------------------
/test.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onemolegames/react-native-toast-native/e18d75dd1dd173700a5a6abdc9284bd6da2705bb/test.gif
--------------------------------------------------------------------------------