I want to show view from camera with opaque frame and transparent center. Something like in the picture (black part is a view from camera). I'm looking for solution with pure react-native components, no additional libs (like https://github.com/gilbox/react-native-masked-view), without adding fullscreen image with transparent center or other hacks.
Javascript – React native: transparent view inside opaque view
iosjavascriptreact-native
Related Solutions
Well, the problem is that the variable i
, within each of your anonymous functions, is bound to the same variable outside of the function.
ES6 solution: let
ECMAScript 6 (ES6) introduces new let
and const
keywords that are scoped differently than var
-based variables. For example, in a loop with a let
-based index, each iteration through the loop will have a new variable i
with loop scope, so your code would work as you expect. There are many resources, but I'd recommend 2ality's block-scoping post as a great source of information.
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let
but get the above wrong (they don't create a new i
each time, so all the functions above would log 3 like they would if we used var
). Edge 14 finally gets it right.
ES5.1 solution: forEach
With the relatively widespread availability of the Array.prototype.forEach
function (in 2015), it's worth noting that in those situations involving iteration primarily over an array of values, .forEach()
provides a clean, natural way to get a distinct closure for every iteration. That is, assuming you've got some sort of array containing values (DOM references, objects, whatever), and the problem arises of setting up callbacks specific to each element, you can do this:
var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});
The idea is that each invocation of the callback function used with the .forEach
loop will be its own closure. The parameter passed in to that handler is the array element specific to that particular step of the iteration. If it's used in an asynchronous callback, it won't collide with any of the other callbacks established at other steps of the iteration.
If you happen to be working in jQuery, the $.each()
function gives you a similar capability.
Classic solution: Closures
What you want to do is bind the variable within each function to a separate, unchanging value outside of the function:
var funcs = [];
function createfunc(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
Since there is no block scope in JavaScript - only function scope - by wrapping the function creation in a new function, you ensure that the value of "i" remains as you intended.
This question seems to be very popular here on Stack Overflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.
I hope this answer is clear enough for people to understand and that I have not missed anything.
Passing Data Forward
Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.
For this example, we will have ViewControllerA
and ViewControllerB
To pass a BOOL
value from ViewControllerA
to ViewControllerB
we would do the following.
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
so use an#import "ViewControllerB.h"
Then where you want to load the view, for example, didSelectRowAtIndex
or some IBAction
, you need to set the property in ViewControllerB
before you push it onto the navigation stack.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
This will set isSomethingEnabled
in ViewControllerB
to BOOL
value YES
.
Passing Data Forward using Segues
If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
So to pass a BOOL
from ViewControllerA
to ViewControllerB
we would do the following:
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
, so use an#import "ViewControllerB.h"
Create the segue from
ViewControllerA
toViewControllerB
on the storyboard and give it an identifier. In this example we'll call it"showDetailSegue"
Next, we need to add the method to
ViewControllerA
that is called when any segue is performed. Because of this we need to detect which segue was called and then do something. In our example, we will check for"showDetailSegue"
and if that's performed, we will pass ourBOOL
value toViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if([segue.identifier isEqualToString:@"showDetailSegue"]){ ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController; controller.isSomethingEnabled = YES; } }
If you have your views embedded in a navigation controller, you need to change the method above slightly to the following
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
controller.isSomethingEnabled = YES;
}
}
This will set isSomethingEnabled
in ViewControllerB
to BOOL
value YES
.
Passing Data Back
To pass data back from ViewControllerB
to ViewControllerA
you need to use Protocols and Delegates or Blocks, the latter can be used as a loosely coupled mechanism for callbacks.
To do this we will make ViewControllerA
a delegate of ViewControllerB
. This allows ViewControllerB
to send a message back to ViewControllerA
enabling us to send data back.
For ViewControllerA
to be a delegate of ViewControllerB
it must conform to ViewControllerB
's protocol which we have to specify. This tells ViewControllerA
which methods it must implement.
In
ViewControllerB.h
, below the#import
, but above@interface
you specify the protocol.@class ViewControllerB; @protocol ViewControllerBDelegate <NSObject> - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; @end
Next still in the
ViewControllerB.h
, you need to set up adelegate
property and synthesize inViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
In
ViewControllerB
we call a message on thedelegate
when we pop the view controller.NSString *itemToPassBack = @"Pass this value back to ViewControllerA"; [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
That's it for
ViewControllerB
. Now inViewControllerA.h
, tellViewControllerA
to importViewControllerB
and conform to its protocol.#import "ViewControllerB.h" @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
In
ViewControllerA.m
implement the following method from our protocol- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog(@"This was returned from ViewControllerB %@", item); }
Before pushing
viewControllerB
to navigation stack we need to tellViewControllerB
thatViewControllerA
is its delegate, otherwise we will get an error.ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.delegate = self [[self navigationController] pushViewController:viewControllerB animated:YES];
References
- Using Delegation to Communicate With Other View Controllers in the View Controller Programming Guide
- Delegate Pattern
NSNotification center
It's another way to pass data.
// Add an observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];
-(void) handleDeepLinking:(NSNotification *) notification {
id someObject = notification.object // Some custom object that was passed with notification fire.
}
// Post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];
Passing Data back from one class to another (A class can be any controller, Network/session manager, UIView subclass or any other class)
Blocks are anonymous functions.
This example passes data from Controller B to Controller A
Define a block
@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h
Add block handler (listener)
Where you need a value (for example, you need your API response in ControllerA or you need ContorllerB data on A)
// In ContollerA.m
- (void)viewDidLoad {
[super viewDidLoad];
__unsafe_unretained typeof(self) weakSelf = self;
self.selectedVoucherBlock = ^(NSString *voucher) {
weakSelf->someLabel.text = voucher;
};
}
Go to Controller B
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
[self.navigationController pushViewController:vc animated:NO];
Fire block
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
NSString *voucher = vouchersArray[indexPath.row];
if (sourceVC.selectVoucherBlock) {
sourceVC.selectVoucherBlock(voucher);
}
[self.navigationController popToViewController:sourceVC animated:YES];
}
Related Topic
- Javascript – How to access the correct `this` inside a callback
- Javascript – Loop inside React JSX
- Asp – fileUpload control appearance
- Ios – Is it possible to run IPhone apps on a virtual machine
- Javascript – Example of Navigation between views in React Native Android
- Javascript – the difference between React Native and React
- Css – React native camera with a transparent view for barcode scanner mask
Best Answer
I found simple solution, I added
View
, transparent inside with opaque border, something like this: