/// Configures and adds primary label view public static void AddInstructionView(this MaterialShowcase materialShowcase, CGPoint atCenter) { materialShowcase.instructionView = new MaterialShowcaseInstructionView(); materialShowcase.instructionView.primaryTextFont = materialShowcase.primaryTextFont; materialShowcase.instructionView.primaryTextSize = materialShowcase.primaryTextSize; materialShowcase.instructionView.primaryTextColor = materialShowcase.primaryTextColor; materialShowcase.instructionView.primaryText = materialShowcase.primaryText; materialShowcase.instructionView.secondaryTextFont = materialShowcase.secondaryTextFont; materialShowcase.instructionView.secondaryTextSize = materialShowcase.secondaryTextSize; materialShowcase.instructionView.secondaryTextColor = materialShowcase.secondaryTextColor; materialShowcase.instructionView.secondaryText = materialShowcase.secondaryText; // Calculate x position var xPosition = MaterialShowcase.LabelMargin; // Calculate y position float yPosition; if (materialShowcase.GetTargetPosition(materialShowcase.targetView, materialShowcase.containerView) == TargetPosition.Above) { yPosition = (float)atCenter.Y + MaterialShowcase.TextCenterOffset; } else { yPosition = (float)atCenter.Y - MaterialShowcase.TextCenterOffset - MaterialShowcase.LabelDefaultHeight * 2; } materialShowcase.instructionView.Frame = new CGRect( xPosition, yPosition, materialShowcase.containerView.Frame.Width - (xPosition + xPosition), 0); materialShowcase.AddSubview(materialShowcase.instructionView); }
public static float Distance(this MaterialShowcase _materialShowcase, CGPoint _a, CGPoint _b) { var xDist = _a.X - _b.X; var yDist = _a.Y - _b.Y; return((float)Math.Sqrt((xDist * xDist) + (yDist * yDist))); }
private static void RecycleSubviews(this MaterialShowcase materialShowcase) { foreach (var subview in materialShowcase.Subviews) { subview.RemoveFromSuperview(); } }
public static void Show(this MaterialShowcase materialShowcase, bool animated = true, Action completionHandler = null) { materialShowcase.InitViews(); materialShowcase.Alpha = .0f; materialShowcase.containerView.AddSubview(materialShowcase); materialShowcase.LayoutIfNeeded(); var scale = new nfloat(MaterialShowcase.TargetHolderRadius / (materialShowcase.backgroundView.Frame.Width * .5)); var center = materialShowcase.backgroundView.Center; materialShowcase.backgroundView.Transform = CGAffineTransform.MakeScale(scale, scale); // Initial set to support animation materialShowcase.backgroundView.Center = materialShowcase.targetHolderView.Center; if (animated) { UIView.Animate(materialShowcase.aniComeInDuration, () => { materialShowcase.targetHolderView.Transform = CGAffineTransform.MakeScale(1, 1); materialShowcase.backgroundView.Transform = CGAffineTransform.MakeScale(1, 1); materialShowcase.backgroundView.Center = center; materialShowcase.Alpha = 1.0f; }, () => { materialShowcase.StartAnimation(); }); } else { materialShowcase.Alpha = 1.0f; } // Handler user's action after showing. completionHandler?.Invoke(); }
/// Add background which is a big circle public static void AddBackground(this MaterialShowcase materialShowcase) { float radius; float targetViewPadding = 7; var center = materialShowcase.GetOuterCircleCenterPoint(materialShowcase.targetCopyView); if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && UIDevice.CurrentDevice.Orientation.IsLandscape()) { radius = (float)materialShowcase.instructionView.Frame.Width - SideMenuWidth; } else { radius = materialShowcase.GetOuterCircleRadius(center, materialShowcase.instructionView.Frame, materialShowcase.targetCopyView.Frame); } materialShowcase.backgroundView = new UIView(new CGRect(0, 0, radius * 2, radius * 2)) { Center = center }; var color = materialShowcase.backgroundPromptColor.ColorWithAlpha(materialShowcase.backgroundPromptColorAlpha); materialShowcase.backgroundView.AsCircleWithTransparentCenter(color, (float)(materialShowcase.targetHolderView.Bounds.Width * .5f - targetViewPadding)); materialShowcase.InsertSubviewBelow(materialShowcase.backgroundView, materialShowcase.instructionView); }
/// Handles user's tap public static UIGestureRecognizer TapGestureRecoganizer(this MaterialShowcase materialShowcase) { return(new UITapGestureRecognizer(() => materialShowcase.TapGestureSelector()) { NumberOfTapsRequired = 1, NumberOfTouchesRequired = 1 }); }
/// A background view which add ripple animation when showing target view public static void AddTargetRipple(this MaterialShowcase materialShowcase, CGPoint atCenter) { materialShowcase.targetRippleView = new UIView(new CGRect(0, 0, materialShowcase.targetHolderRadius * 2, materialShowcase.targetHolderRadius * 2)); materialShowcase.targetRippleView.Center = atCenter; materialShowcase.targetRippleView.BackgroundColor = materialShowcase.aniRippleColor; materialShowcase.targetRippleView.Alpha = .0f; //set it invisible materialShowcase.targetRippleView.AsCircle(); materialShowcase.AddSubview(materialShowcase.targetRippleView); }
public static float MaxDistance(this MaterialShowcase _materialShowcase, CGPoint _fromPoint, CGRect _toRect) { var tl = _materialShowcase.Distance(_fromPoint, new CGPoint(_toRect.GetMinX(), _toRect.GetMinY())); var tr = _materialShowcase.Distance(_fromPoint, new CGPoint(_toRect.GetMaxX(), _toRect.GetMinY())); var bl = _materialShowcase.Distance(_fromPoint, new CGPoint(_toRect.GetMinX(), _toRect.GetMaxY())); var br = _materialShowcase.Distance(_fromPoint, new CGPoint(_toRect.GetMaxX(), _toRect.GetMaxY())); return(Math.Max(tl, Math.Max(tr, Math.Max(bl, br)))); }
/// Sets a UITableViewCell as target public static void SetTargetView(this MaterialShowcase materialShowcase, UITableView tableView, int section, int row) { var indexPath = NSIndexPath.FromRowSection(row, section); materialShowcase.targetView = tableView.CellAt(indexPath)?.ContentView; // for table viewcell, we do not need target holder (circle view) // therefore, set its radius = 0 materialShowcase.targetHolderRadius = 0; }
/// Sets a UIBarButtonItem as target public static void SetTargetView(this MaterialShowcase materialShowcase, UIBarButtonItem barButtonItem) { var view = barButtonItem.ValueForKey(new NSString("view")); if (view != null && view is UIView) { materialShowcase.targetView = ((UIView)view).Subviews.First(); } materialShowcase.backgroundPromptColor = UINavigationBar.Appearance.TintColor; }
public static void Configure(this MaterialShowcase materialShowcase) { materialShowcase.BackgroundColor = UIColor.Clear; var window = UIApplication.SharedApplication.Delegate?.GetWindow(); if (window != null) { materialShowcase.containerView = window; materialShowcase.SetDefaultProperties(); } }
/// A circle-shape background view of target view public static void AddTargetHolder(this MaterialShowcase materialShowcase, CGPoint atCenter) { materialShowcase.hiddenTargetHolderView = new UIView(); materialShowcase.hiddenTargetHolderView.Hidden = true; materialShowcase.targetHolderView = new UIView(new CGRect(0, 0, materialShowcase.targetHolderRadius * 2, materialShowcase.targetHolderRadius * 2)); materialShowcase.targetHolderView.Center = atCenter; materialShowcase.targetHolderView.BackgroundColor = materialShowcase.targetHolderColor; materialShowcase.targetHolderView.AsCircle(); materialShowcase.hiddenTargetHolderView.Frame = materialShowcase.targetHolderView.Frame; materialShowcase.targetHolderView.Transform = CGAffineTransform.MakeScale(1 / MaterialShowcase.AniTargetHolderScale, 1 / MaterialShowcase.AniTargetHolderScale); // Initial set to support animation materialShowcase.AddSubview(materialShowcase.hiddenTargetHolderView); materialShowcase.AddSubview(materialShowcase.targetHolderView); }
/// Detects the position of target view relative to its container public static TargetPosition GetTargetPosition(this MaterialShowcase materialShowcase, UIView target, UIView container) { var center = materialShowcase.CalculateCenter(materialShowcase.targetView, container); if (center.Y < container.Frame.Height * .5f) { return(TargetPosition.Above); } else { return(TargetPosition.Below); } }
public static float GetOuterCircleRadius(this MaterialShowcase _materialShowcase, CGPoint _center, CGRect _textBounds, CGRect _targetBounds) { var targetCenterX = _targetBounds.GetMidX(); var targetCenterY = _targetBounds.GetMidY(); var expandedRadius = new nfloat(1.1 * MaterialShowcase.TargetHolderRadius); var expandedBounds = new CGRect(targetCenterX, targetCenterY, 0, 0); expandedBounds.Inset(-expandedRadius, -expandedRadius); var textRadius = _materialShowcase.MaxDistance(_center, _textBounds); var targetRadius = _materialShowcase.MaxDistance(_center, expandedBounds); return(Math.Max(textRadius, targetRadius) + 40); }
/// Sets a UITabBar Item as target public static void SetTargetView(this MaterialShowcase materialShowcase, UITabBar tabBar, int itemIndex) { var tabBarItems = OrderedTabBarItemViews(tabBar); if (itemIndex < tabBarItems.Count) { materialShowcase.targetView = tabBarItems[itemIndex]; materialShowcase.targetTintColor = tabBar.TintColor; materialShowcase.backgroundPromptColor = tabBar.TintColor; } else { Console.WriteLine("The tab bar item index is out of range"); } }
public static void InitViews(this MaterialShowcase materialShowcase) { var center = materialShowcase.CalculateCenter(materialShowcase.targetView, materialShowcase.containerView); materialShowcase.AddTargetRipple(center); materialShowcase.AddTargetHolder(center); materialShowcase.AddTarget(center); materialShowcase.AddInstructionView(center); materialShowcase.instructionView.LayoutIfNeeded(); materialShowcase.AddBackground(); // Add gesture recognizer for both container and its subview materialShowcase.AddGestureRecognizer(materialShowcase.TapGestureRecoganizer()); // Disable subview interaction to let users click to general view only foreach (var subView in materialShowcase.Subviews) { subView.UserInteractionEnabled = false; } }
/// Create a copy view of target view /// It helps us not to affect the original target view public static void AddTarget(this MaterialShowcase materialShowcase, CGPoint atCenter) { materialShowcase.targetCopyView = materialShowcase.targetView.SnapshotView(true); if (materialShowcase.shouldSetTintColor) { materialShowcase.targetCopyView.SetTintColor(materialShowcase.targetTintColor, true); if (materialShowcase.targetCopyView is UIButton) { UIButton button = materialShowcase.targetView as UIButton; UIButton buttonCopy = materialShowcase.targetCopyView as UIButton; buttonCopy.SetImage(button.ImageForState(UIControlState.Normal)?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), UIControlState.Normal); buttonCopy.SetTitleColor(materialShowcase.targetTintColor, UIControlState.Normal); buttonCopy.Enabled = true; } else if (materialShowcase.targetCopyView is UIImageView) { UIImageView imageView = materialShowcase.targetView as UIImageView; UIImageView imageViewCopy = materialShowcase.targetCopyView as UIImageView; imageViewCopy.Image = imageView.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate); } else if (materialShowcase.targetCopyView.Subviews.FirstOrDefault() is UIImageView && materialShowcase.targetCopyView.Subviews.LastOrDefault() is UILabel) { UIImageView imageViewCopy = materialShowcase.targetCopyView.Subviews.First() as UIImageView; UILabel labelCopy = materialShowcase.targetCopyView.Subviews.Last() as UILabel; UIImageView imageView = (UIImageView)materialShowcase.targetView.Subviews.First(); imageViewCopy.Image = imageView.Image?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate); labelCopy.TextColor = materialShowcase.targetTintColor; } else if (materialShowcase.targetCopyView is UILabel) { (materialShowcase.targetCopyView as UILabel).TextColor = materialShowcase.targetTintColor; } } var width = materialShowcase.targetCopyView.Frame.Width; var height = materialShowcase.targetCopyView.Frame.Height; materialShowcase.targetCopyView.Frame = new CGRect(0, 0, width, height); materialShowcase.targetCopyView.Center = atCenter; materialShowcase.targetCopyView.TranslatesAutoresizingMaskIntoConstraints = true; materialShowcase.AddSubview(materialShowcase.targetCopyView); }
public static CGPoint GetOuterCircleCenterPoint(this MaterialShowcase _materialShowcase, UIView _target) { if (_materialShowcase.IsInGutter(_target.Center)) { return(_target.Center); } var targetRadius = Math.Max(_target.Frame.Width, _target.Frame.Height) * .5f + MaterialShowcase.TargetPadding; var totalTextHeight = _materialShowcase.instructionView.Frame.Height; var onTop = _materialShowcase.GetTargetPosition(_materialShowcase.targetView, _materialShowcase.containerView) == MaterialShowcaseExtension.TargetPosition.Below; var left = Math.Min(_materialShowcase.instructionView.Frame.GetMinX(), _target.Frame.GetMinX() - targetRadius); var right = Math.Max(_materialShowcase.instructionView.Frame.GetMaxX(), _target.Frame.GetMaxX() + targetRadius); var titleHeight = _materialShowcase.instructionView.primaryLabel.Frame.Height; var centerY = onTop ? _target.Center.Y - MaterialShowcase.TargetHolderRadius - MaterialShowcase.TargetPadding - totalTextHeight + titleHeight : _target.Center.Y + MaterialShowcase.TargetHolderRadius + MaterialShowcase.TargetPadding + titleHeight; return(new CGPoint((left + right) * .5f, centerY)); }
/// Configures and adds primary label view public static void AddInstructionView(this MaterialShowcase materialShowcase, CGPoint atCenter) { materialShowcase.instructionView = new MaterialShowcaseInstructionView(); materialShowcase.instructionView.primaryTextFont = materialShowcase.primaryTextFont; materialShowcase.instructionView.primaryTextSize = materialShowcase.primaryTextSize; materialShowcase.instructionView.primaryTextColor = materialShowcase.primaryTextColor; materialShowcase.instructionView.primaryText = materialShowcase.primaryText; materialShowcase.instructionView.secondaryTextFont = materialShowcase.secondaryTextFont; materialShowcase.instructionView.secondaryTextSize = materialShowcase.secondaryTextSize; materialShowcase.instructionView.secondaryTextColor = materialShowcase.secondaryTextColor; materialShowcase.instructionView.secondaryText = materialShowcase.secondaryText; materialShowcase.instructionView.dismissText = materialShowcase.dismissText; materialShowcase.instructionView.dismissTextFont = materialShowcase.dismissTextFont; materialShowcase.instructionView.dismissTextColor = materialShowcase.dismissTextColor; materialShowcase.instructionView.dismissBackgroundColor = materialShowcase.dismissBackgroundColor; // Calculate x position var xPosition = UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && UIDevice.CurrentDevice.Orientation.IsLandscape() ? MaterialShowcase.LabelMargin + SideMenuWidth : MaterialShowcase.LabelMargin; // Calculate y position float yPosition; if (materialShowcase.GetTargetPosition(materialShowcase.targetView, materialShowcase.containerView) == TargetPosition.Above) { yPosition = (float)atCenter.Y + MaterialShowcase.TextCenterOffset; } else { yPosition = (float)atCenter.Y - MaterialShowcase.TextCenterOffset - MaterialShowcase.LabelDefaultHeight * 2; } materialShowcase.instructionView.Frame = new CGRect( xPosition, yPosition, materialShowcase.containerView.Frame.Width - (xPosition + xPosition), 0); materialShowcase.AddSubview(materialShowcase.instructionView); }
/// Default action when dimissing showcase /// Notifies delegate, removes views, and handles out-going animation public static void CompleteShowcase(this MaterialShowcase materialShowcase, bool animated = true) { if (materialShowcase.showcaseDelegate != null) { materialShowcase.showcaseDelegate.ShowCaseWillDismiss(); } if (animated) { materialShowcase.targetRippleView.RemoveFromSuperview(); UIView.AnimateKeyframes(materialShowcase.aniGoOutDuration, 0, UIViewKeyframeAnimationOptions.CalculationModeLinear, () => { UIView.AddKeyframeWithRelativeStartTime(0, .6f, () => { materialShowcase.targetHolderView.Transform = CGAffineTransform.MakeScale(.4f, .4f); materialShowcase.backgroundView.Transform = CGAffineTransform.MakeScale(1.3f, 1.3f); materialShowcase.backgroundView.Alpha = 0; }); UIView.AddKeyframeWithRelativeStartTime(.6f, .4f, () => { materialShowcase.Alpha = 0; }); }, (success) => { // Recycle subviews materialShowcase.RecycleSubviews(); // Remove it from current screen materialShowcase.RemoveFromSuperview(); }); } else { // Recycle subviews materialShowcase.RecycleSubviews(); // Remove it from current screen materialShowcase.RemoveFromSuperview(); } if (materialShowcase.showcaseDelegate != null) { materialShowcase.showcaseDelegate.ShowCaseDidDismiss(); } }
/// Sets a general UIView as target public static void SetTargetView(this MaterialShowcase materialShowcase, UIView view) { materialShowcase.targetView = view; if (materialShowcase.targetView is UILabel) { UILabel label = materialShowcase.targetView as UILabel; materialShowcase.targetTintColor = label.TextColor; materialShowcase.backgroundPromptColor = label.TextColor; } else if (materialShowcase.targetView is UIButton) { UIButton button = materialShowcase.targetView as UIButton; var tintColor = button.TitleColor(UIControlState.Normal); materialShowcase.targetTintColor = tintColor; materialShowcase.backgroundPromptColor = tintColor; } else { materialShowcase.targetTintColor = materialShowcase.targetView.TintColor; materialShowcase.backgroundPromptColor = materialShowcase.targetView.TintColor; } }
/// Add background which is a big circle public static void AddBackground(this MaterialShowcase materialShowcase) { float radius; var center = materialShowcase.GetOuterCircleCenterPoint(materialShowcase.targetCopyView); if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad) { radius = 300.0f; } else { radius = materialShowcase.GetOuterCircleRadius(center, materialShowcase.instructionView.Frame, materialShowcase.targetCopyView.Frame); } materialShowcase.backgroundView = new UIView(new CGRect(0, 0, radius * 2, radius * 2)) { Center = center, BackgroundColor = materialShowcase.backgroundPromptColor.ColorWithAlpha(materialShowcase.backgroundPromptColorAlpha) }; materialShowcase.backgroundView.AsCircle(); materialShowcase.InsertSubviewBelow(materialShowcase.backgroundView, materialShowcase.targetRippleView); }
public static void SetDefaultProperties(this MaterialShowcase materialShowcase) { // Background materialShowcase.backgroundPromptColor = MaterialShowcase.BackgroundDefaultColor; materialShowcase.backgroundPromptColorAlpha = MaterialShowcase.BackgroundAlpha; // Target view materialShowcase.targetTintColor = MaterialShowcase.BackgroundDefaultColor; materialShowcase.targetHolderColor = MaterialShowcase.TargetHolderColor; materialShowcase.targetHolderRadius = MaterialShowcase.TargetHolderRadius; // Text materialShowcase.primaryText = MaterialShowcaseInstructionView.PrimaryDefaultText; materialShowcase.secondaryText = MaterialShowcaseInstructionView.SecondaryDefaultText; materialShowcase.primaryTextColor = MaterialShowcaseInstructionView.PrimaryTextColor; materialShowcase.secondaryTextColor = MaterialShowcaseInstructionView.SecondaryTextColor; materialShowcase.primaryTextSize = MaterialShowcaseInstructionView.PrimaryTextSize; materialShowcase.secondaryTextSize = MaterialShowcaseInstructionView.SecondaryTextSize; // Animation materialShowcase.aniComeInDuration = MaterialShowcase.AniComeInDuration; materialShowcase.aniGoOutDuration = MaterialShowcase.AniGoOutDuration; materialShowcase.aniRippleAlpha = MaterialShowcase.AniRippleAlpha; materialShowcase.aniRippleColor = MaterialShowcase.AniRippleColor; materialShowcase.aniRippleScale = MaterialShowcase.AniRippleScale; }
public static void StartAnimation(this MaterialShowcase materialShowcase) { //UIViewAnimationOptions optionsOLD = UIViewAnimationOptions.CurveEaseInOut | UIViewAnimationOptions.Repeat; UIViewKeyframeAnimationOptions options = UIViewKeyframeAnimationOptions.Repeat | 0 << 16; UIView.AnimateKeyframes(1, 0, options, () => { UIView.AddKeyframeWithRelativeStartTime(0, .5f, () => { materialShowcase.targetRippleView.Alpha = MaterialShowcase.AniRippleAlpha; materialShowcase.targetHolderView.Transform = CGAffineTransform.MakeScale(1.1f, 1.1f); materialShowcase.targetRippleView.Transform = CGAffineTransform.MakeScale(1.1f, 1.1f); }); UIView.AddKeyframeWithRelativeStartTime(.5f, .5f, () => { materialShowcase.targetHolderView.Transform = CGAffineTransform.MakeIdentity(); materialShowcase.targetRippleView.Alpha = 0; materialShowcase.targetRippleView.Transform = CGAffineTransform.MakeScale(materialShowcase.aniRippleScale, materialShowcase.aniRippleScale); }); }, (completion) => { Console.WriteLine("ok"); }); }
public static bool IsInGutter(this MaterialShowcase _materialShowcase, CGPoint _center) { return(_center.Y < MaterialShowcase.OffsetThreshold || _materialShowcase.containerView.Frame.Height - _center.Y < MaterialShowcase.OffsetThreshold); }
private static void TapGestureSelector(this MaterialShowcase materialShowcase) { materialShowcase.CompleteShowcase(); }
// Calculates the center point based on targetview public static CGPoint CalculateCenter(this MaterialShowcase materialShowcase, UIView targetView, UIView containerView) { var targetRect = targetView.ConvertRectToCoordinateSpace(targetView.Bounds, containerView); return(targetRect.Center()); }