This commit is contained in:
EddyVerbruggen 2016-01-27 20:49:03 +01:00
parent ac0746b9b9
commit 5f4a0f5636
9 changed files with 128 additions and 44 deletions

View File

@ -19,6 +19,7 @@ for Android, iOS and WP8, by [Eddy Verbruggen](http://www.x-services.nl/phonegap
3. [Manually](#manually)
3. [PhoneGap Build](#phonegap-build)
4. [Usage](#4-usage)
4. [Styling](#styling)
5. [Credits](#5-credits)
6. [Changelog](#6-changelog)
7. [License](#7-license)
@ -48,10 +49,18 @@ iOS
![ScreenShot](screenshots/screenshot-ios-toast.png)
A few styling options
![ScreenShot](screenshots/styling-green.png)
![ScreenShot](screenshots/styling-red.png)
Android
![ScreenShot](screenshots/screenshot-android-toast.png)
Windows Phone 8
![ScreenShot](screenshots/screenshot-wp8.jpg)
@ -203,6 +212,30 @@ called again. You can distinguish between those events of course:
);
```
### Styling
Since version 2.4.0 you can pass an optional `styling` object to the plugin.
The defaults make sure the Toast looks the same as when you would not pass in the `styling` object at all.
Note that on WP this object is currently ignored.
```js
window.plugins.toast.showWithOptions({
message: "hey there",
duration: "short",
position: "bottom",
styling: {
opacity: 0.75, // 0.0 (transparent) to 1.0 (opaque). Default 0.8
backgroundColor: '#FF0000', // make sure you use #RRGGBB. Default #333333
cornerRadius: 16, // minimum is 0 (square). iOS default 20, Android default 100
horizontalPadding: 20, // iOS default 16, Android default 50
verticalPadding: 16 // iOS default 12, Android default 30
}
});
```
Tip: if you need to pass different values for iOS and Android you can use fi. the device plugin
to determine the platform and pass `opacity: isAndroid() ? 0.7 : 0.9`.
### WP8 quirks
The WP8 implementation needs a little more work, but it's perfectly useable when you keep this in mind:
* You can't show two Toasts simultaneously.
@ -217,15 +250,12 @@ The Android code was entirely created by me.
For iOS most credits go to this excellent [Toast for iOS project by Charles Scalesse] (https://github.com/scalessec/Toast).
## 6. CHANGELOG
2.3.2: The click event introduced with 2.3.0 did not work with Android 5+.
2.3.0: The plugin will now report back to JS if Toasts were tapped by the user.
2.0.1: iOS messages are hidden when another one is shown. [Thanks Richie Min!](https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin/pull/13)
2.0: WP8 support
1.0: initial version supporting Android and iOS
- 2.4.0: You can now style the Toast with a number of properties. See
- 2.3.2: The click event introduced with 2.3.0 did not work with Android 5+.
- 2.3.0: The plugin will now report back to JS if Toasts were tapped by the user.
- 2.0.1: iOS messages are hidden when another one is shown. [Thanks Richie Min!](https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin/pull/13)
- 2.0: WP8 support
- 1.0: initial version supporting Android and iOS
## 7. License

View File

@ -1,6 +1,6 @@
{
"name": "cordova-plugin-x-toast",
"version": "2.3.2",
"version": "2.4.0",
"description": "This plugin allows you to show a Toast. A Toast is a little non intrusive buttonless popup which automatically disappears.",
"cordova": {
"id": "cordova-plugin-x-toast",

View File

@ -2,7 +2,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-x-toast"
version="2.3.2">
version="2.4.0">
<name>Toast</name>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
screenshots/styling-red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,5 +1,7 @@
package nl.xservices.plugins;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
@ -37,7 +39,7 @@ public class Toast extends CordovaPlugin {
private android.widget.Toast mostRecentToast;
private ViewGroup viewGroup;
private static final boolean IS_AT_LEAST_ANDROID5 = Build.VERSION.SDK_INT >= 21;
private static final boolean IS_AT_LEAST_LOLLIPOP = Build.VERSION.SDK_INT >= 21;
// note that webView.isPaused() is not Xwalk compatible, so tracking it poor-man style
private boolean isPaused;
@ -65,20 +67,15 @@ public class Toast extends CordovaPlugin {
final String position = options.getString("position");
final int addPixelsY = options.has("addPixelsY") ? options.getInt("addPixelsY") : 0;
final JSONObject data = options.has("data") ? options.getJSONObject("data") : null;
final JSONObject styling = options.optJSONObject("styling");
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
final android.widget.Toast toast = android.widget.Toast.makeText(
IS_AT_LEAST_ANDROID5 ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(),
IS_AT_LEAST_LOLLIPOP ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(),
message,
"short".equals(duration) ? android.widget.Toast.LENGTH_SHORT : android.widget.Toast.LENGTH_LONG);
// if we want to change the background color some day, we can use this
// try {
// final Method setTintMethod = Drawable.class.getMethod("setTint", int.class);
// setTintMethod.invoke(toast.getView().getBackground(), Color.RED); // default is Color.DKGRAY
// } catch (Exception ignore) {
// }
if ("top".equals(position)) {
toast.setGravity(GRAVITY_TOP, 0, BASE_TOP_BOTTOM_OFFSET + addPixelsY);
} else if ("bottom".equals(position)) {
@ -90,9 +87,32 @@ public class Toast extends CordovaPlugin {
return;
}
// if one of the custom layout options have been passed in, draw our own shape
if (styling != null && Build.VERSION.SDK_INT >= 16) {
// the defaults mimic the default toast as close as possible
final String backgroundColor = styling.optString("backgroundColor", "#333333");
final double opacity = styling.optDouble("opacity", 0.8);
final int cornerRadius = styling.optInt("cornerRadius", 100);
final int horizontalPadding = styling.optInt("horizontalPadding", 50);
final int verticalPadding = styling.optInt("verticalPadding", 30);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(cornerRadius);
shape.setAlpha((int)(opacity * 255)); // 0-255, where 0 is an invisible background
shape.setColor(Color.parseColor(backgroundColor));
toast.getView().setBackground(shape);
toast.getView().setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
// this gives the toast a very subtle shadow on newer devices
if (Build.VERSION.SDK_INT >= 21) {
toast.getView().setElevation(6);
}
}
// On Android >= 5 you can no longer rely on the 'toast.getView().setOnTouchListener',
// so created something funky that compares the Toast position to the tap coordinates.
if (IS_AT_LEAST_ANDROID5) {
if (IS_AT_LEAST_LOLLIPOP) {
getViewGroup().setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {

View File

@ -6,7 +6,7 @@
// each makeToast method creates a view and displays it as toast
- (void)makeToast:(NSString *)message;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY data:(NSDictionary*)data commandDelegate:(id <CDVCommandDelegate>)commandDelegate callbackId:(NSString *)callbackId;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY data:(NSDictionary*)data styling:(NSDictionary*)styling commandDelegate:(id <CDVCommandDelegate>)commandDelegate callbackId:(NSString *)callbackId;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position image:(UIImage *)image;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title image:(UIImage *)image;

View File

@ -53,6 +53,7 @@ static id commandDelegate;
static id callbackId;
static id msg;
static id data;
static id styling;
@interface UIView (ToastPrivate)
@ -79,11 +80,20 @@ static id data;
[self showToast:toast duration:duration position:position];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY data:(NSDictionary*)_data commandDelegate:(id <CDVCommandDelegate>)_commandDelegate callbackId:(NSString *)_callbackId {
- (void)makeToast:(NSString *)message
duration:(NSTimeInterval)duration
position:(id)position addPixelsY:(int)addPixelsY
data:(NSDictionary*)_data
styling:(NSDictionary*)_styling
commandDelegate:(id <CDVCommandDelegate>)_commandDelegate
callbackId:(NSString *)_callbackId {
commandDelegate = _commandDelegate;
callbackId = _callbackId;
msg = message;
data = _data;
styling = _styling;
UIView *toast = [self viewForMessage:message title:nil image:nil];
[self showToast:toast duration:duration position:position addedPixelsY:addPixelsY];
}
@ -295,7 +305,9 @@ static id data;
// create the parent view
UIView *wrapperView = [[UIView alloc] init];
wrapperView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
wrapperView.layer.cornerRadius = CSToastCornerRadius;
NSNumber * cornerRadius = styling[@"cornerRadius"];
wrapperView.layer.cornerRadius = cornerRadius == nil ? CSToastCornerRadius : [cornerRadius floatValue];
if (CSToastDisplayShadow) {
wrapperView.layer.shadowColor = [UIColor blackColor].CGColor;
@ -304,12 +316,23 @@ static id data;
wrapperView.layer.shadowOffset = CSToastShadowOffset;
}
wrapperView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:CSToastOpacity];
NSString * backgroundColor = styling[@"backgroundColor"];
UIColor *theColor = backgroundColor == nil ? [UIColor blackColor] : [self colorFromHexString:backgroundColor];
NSNumber * opacity = styling[@"opacity"];
CGFloat theOpacity = opacity == nil ? CSToastOpacity : [opacity floatValue];
NSNumber * horizontalPadding = styling[@"horizontalPadding"];
NSNumber * verticalPadding = styling[@"verticalPadding"];
CGFloat theHorizontalPadding = horizontalPadding == nil ? CSToastHorizontalPadding : [horizontalPadding floatValue];
CGFloat theVerticalPadding = verticalPadding == nil ? CSToastVerticalPadding : [verticalPadding floatValue];
wrapperView.backgroundColor = [theColor colorWithAlphaComponent:theOpacity];
if(image != nil) {
imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.frame = CGRectMake(CSToastHorizontalPadding, CSToastVerticalPadding, CSToastImageViewWidth, CSToastImageViewHeight);
imageView.frame = CGRectMake(theHorizontalPadding, theVerticalPadding, CSToastImageViewWidth, CSToastImageViewHeight);
}
CGFloat imageWidth, imageHeight, imageLeft;
@ -318,7 +341,7 @@ static id data;
if(imageView != nil) {
imageWidth = imageView.bounds.size.width;
imageHeight = imageView.bounds.size.height;
imageLeft = CSToastHorizontalPadding;
imageLeft = theHorizontalPadding;
} else {
imageWidth = imageHeight = imageLeft = 0.0;
}
@ -362,8 +385,8 @@ static id data;
if(titleLabel != nil) {
titleWidth = titleLabel.bounds.size.width;
titleHeight = titleLabel.bounds.size.height;
titleTop = CSToastVerticalPadding;
titleLeft = imageLeft + imageWidth + CSToastHorizontalPadding;
titleTop = theVerticalPadding;
titleLeft = imageLeft + imageWidth + theHorizontalPadding;
} else {
titleWidth = titleHeight = titleTop = titleLeft = 0.0;
}
@ -374,8 +397,8 @@ static id data;
if(messageLabel != nil) {
messageWidth = messageLabel.bounds.size.width;
messageHeight = messageLabel.bounds.size.height;
messageLeft = imageLeft + imageWidth + CSToastHorizontalPadding;
messageTop = titleTop + titleHeight + CSToastVerticalPadding;
messageLeft = imageLeft + imageWidth + theHorizontalPadding;
messageTop = titleTop + titleHeight + theVerticalPadding;
} else {
messageWidth = messageHeight = messageLeft = messageTop = 0.0;
}
@ -384,8 +407,8 @@ static id data;
CGFloat longerLeft = MAX(titleLeft, messageLeft);
// wrapper width uses the longerWidth or the image width, whatever is larger. same logic applies to the wrapper height
CGFloat wrapperWidth = MAX((imageWidth + (CSToastHorizontalPadding * 2)), (longerLeft + longerWidth + CSToastHorizontalPadding));
CGFloat wrapperHeight = MAX((messageTop + messageHeight + CSToastVerticalPadding), (imageHeight + (CSToastVerticalPadding * 2)));
CGFloat wrapperWidth = MAX((imageWidth + (theHorizontalPadding * 2)), (longerLeft + longerWidth + theHorizontalPadding));
CGFloat wrapperHeight = MAX((messageTop + messageHeight + theVerticalPadding), (imageHeight + (theVerticalPadding * 2)));
wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight);
@ -406,4 +429,13 @@ static id data;
return wrapperView;
}
// Assumes input like "#00FF00" (#RRGGBB)
- (UIColor*) colorFromHexString:(NSString*) hexString {
unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // bypass '#' character
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0 green:((rgbValue & 0xFF00) >> 8) / 255.0 blue:(rgbValue & 0xFF) / 255.0 alpha:1.0];
}
@end

View File

@ -6,13 +6,14 @@
- (void)show:(CDVInvokedUrlCommand*)command {
NSDictionary* options = [command.arguments objectAtIndex:0];
NSDictionary* options = [command argumentAtIndex:0];
NSString *message = [options objectForKey:@"message"];
NSString *duration = [options objectForKey:@"duration"];
NSString *position = [options objectForKey:@"position"];
NSDictionary *data = [options objectForKey:@"data"];
NSNumber *addPixelsY = [options objectForKey:@"addPixelsY"];
NSString *message = options[@"message"];
NSString *duration = options[@"duration"];
NSString *position = options[@"position"];
NSDictionary *data = options[@"data"];
NSNumber *addPixelsY = options[@"addPixelsY"];
NSDictionary *styling = options[@"styling"];
if (![position isEqual: @"top"] && ![position isEqual: @"center"] && ![position isEqual: @"bottom"]) {
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"invalid position. valid options are 'top', 'center' and 'bottom'"];
@ -36,6 +37,7 @@
position:position
addPixelsY:addPixelsY == nil ? 0 : [addPixelsY intValue]
data:data
styling:styling
commandDelegate:self.commandDelegate
callbackId:command.callbackId];