How to access the UIImagePickerController Shutter UiButton from Xamarin.ios - xamarin.forms

i would like to access to the Shutter UiButton from a xamarin.iOS App
so i can do some changes on it, but i'm not able to find it.
so i tried to recreate the UIImagePickerController project in xcode, and i i found it using this code and i'm able to do the changes.
does xamarin.iOS have a different view hierarchy ?
for (index,v) in self.imagePicker.view.subviews.enumerated()
{
print("layer \(index) : \(v)")
for (index2,vv) in v.subviews.enumerated()
{
print("layer \(index, index2) : \(vv)")
for (index3,vvv) in vv.subviews.enumerated()
{
print("layer \(index, index2, index3) : \(vvv)")
for (index4,vvvv) in vvv.subviews.enumerated()
{
print("layer \(index, index2, index3, index4) : \(vvvv)")
for (index5,vvvvv) in vvvv.subviews.enumerated()
{
print("layer \(index, index2, index3, index4, index5) : \(vvvvv)")
for (index6,vvvvvv) in vvvvv.subviews.enumerated()
{
print("layer \(index, index2, index3, index4, index5, index6) : \(vvvvvv)")
if (vvvvvv as? UIButton != nil)
{
var t = String(describing:type(of:vvvvvv))
if(t == "CUShutterButton")
{
print("is button CUShutterButton")
(vvvvvv as! UIButton).setTitleColor(UIColor.red, for: UIControlState.normal)
(vvvvvv as! UIButton).backgroundColor = UIColor.red
v.frame = CGRect.init(x: 0, y: 0, width: 500, height: 500)
for (vvvvvvv) in vvvvvv.subviews
{
vvvvvvv.backgroundColor = UIColor.red
}
}
}
}
}
}
}
}
}
Image : can't find the UiButton from vs

Xamarin doesn't have a different view hierarchy. Your problem is in those lines:
var t = String(describing:type(of:vvvvvv))
if(t == "CUShutterButton")
I am not sure how you have translated this to Xamarin (which may influence the results too), but the string description of the type of the class can be different. So you need to list all strings, find the right one and use it in your if statement.

Related

How to change the Status Bar in Xamarin Forms ContentPage using AppShell?

I am using the new concept AppShell, and I am doing the following flow
App.MainPage = new AppShell();
then I do
protected async override void OnStart()
{
await Shell.Current.GoToAsync($"//{nameof(LoginPage)}");
}
With this I have a ForgetPasswordPage, from LoginViewModel I do
await Shell.Current.GoToAsync($"//{nameof(ForgetPasswordPage)}");
The point is if I do this
var color = new Color(33, 150, 243);
Xamarin.Essentials.Platform.CurrentActivity.Window.SetStatusBarColor(color);
Inside the Create method from Android the StatusBar has the color I defined.
Now where is the method for iOS, like this?
I tried theses solutions
How to change the status bar color without a navigation page
Xamarin.Forms.Shell: how to manage StatusBar color
https://github.com/georgemichailou/ShaXam/
Without succeed...
Someone can explain, how to change the status code but I would like to set it inside my ContentPage, I could use a style, or a simple line of code like this
Xamarin.Essentials.Platform.CurrentActivity.Window.SetStatusBarColor(color);
Which is used in Android project.
I did the steps from the other posts, and I got:
Foundation.MonoTouchException: 'Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: App called -statusBar or -statusBarWindow on UIApplication: this code must be changed as there's no longer a status bar or status bar window. Use the statusBarManager object on the window scene instead.
Native stack trace:
0 CoreFoundation 0x00007fff20422fba __exceptionPreprocess + 242
System.Reflection.TargetInvocationException Message=Exception has been thrown by the target of an invocation
You can take a look at my video here that walks through in details: https://www.youtube.com/watch?v=GKJRR8_DSSs
In general:
Android -
public void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
if (Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.Lollipop)
return;
var activity = Platform.CurrentActivity;
var window = activity.Window;
window.AddFlags(Android.Views.WindowManagerFlags.DrawsSystemBarBackgrounds);
window.ClearFlags(Android.Views.WindowManagerFlags.TranslucentStatus);
window.SetStatusBarColor(color.ToPlatformColor());
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
{
var flag = (Android.Views.StatusBarVisibility)Android.Views.SystemUiFlags.LightStatusBar;
window.DecorView.SystemUiVisibility = darkStatusBarTint ? flag : 0;
}
}
iOS:
public void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
var statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = color.ToPlatformColor();
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
}
else
{
var statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = color.ToPlatformColor();
}
}
var style = darkStatusBarTint ? UIStatusBarStyle.DarkContent : UIStatusBarStyle.LightContent;
UIApplication.SharedApplication.SetStatusBarStyle(style, false);
Xamarin.Essentials.Platform.GetCurrentUIViewController()?.SetNeedsStatusBarAppearanceUpdate();
}

how to get the safearea thickness?

I want place an image in the top of the screen.
so I tried to get the top safearea insets.
var safeArea=On<Xamarin.Forms.PlateformConfiguaration.iOS>().SafeAreaInsets();
safeArea.Top=-safeArea.Top;
Image.Margin=safeArea;
but all the safeArea properties is 0.
hot to get the right thickness?
Firstly , SafeArea is available after iOS 11.0 ,So you should check the version of iOS before you want to get it .
I suggest you can use DependencyService
in Forms ,create the Interface
public interface IGetSafeArea
{
double GetSafeAreaTop();
double GetSafeAreaBottom();
}
in iOS
using UIKit;
using xxx;
namespace xxx.iOS
{
public class GetSafeArea : IGetSafeArea
{
public double GetSafeAreaBottom()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
UIWindow window = UIApplication.SharedApplication.Delegate.GetWindow();
var bottomPadding = window.SafeAreaInsets.Bottom;
return bottomPadding;
}
return 0;
}
public double GetSafeAreaTop()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
UIWindow window = UIApplication.SharedApplication.Delegate.GetWindow();
var topPadding = window.SafeAreaInsets.Top;
return topPadding;
}
return 0;
}
}
}
And invoke the method as you want
var top = DependencyService.Get<IGetSafeArea>().GetSafeAreaTop();

SwiftUI - navigationBarBackButton

How can I change navigationBarBackButton color in SwiftUI? (by
default it's blue)
How can I change navigationBarBackButton text in SwiftUI?
This is my code (an example):
struct ExercisesList : View {
var exercises : [Exercise]
var body: some View {
NavigationView {
List(self.exercises.identified(by: \.number)) {exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
.navigationBarTitle(Text("Exercises"))
}
}
}
By default, the navigationBarBackButton in "ExerciseDetailView" has a text of Exercise and color of blue.
My question is how can I manipulate these two?
Here is a solution. Hope it will help. In this way, you can use custom UIColor also.
struct ExercisesList : View {
var exercises : [Exercise]
var body: some View {
UINavigationBar.appearance().tintColor = UIColor.red
return NavigationView {
List(self.exercises.identified(by: \.number)) { exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
}
.navigationBarTitle(Text("Exercises"))
}
}
Currently, No direct methods are available for that(XCode 11 beta 3).
However You can use UINavigationBar method for that,
see below code :
struct ExercisesList : View {
var exercises : [Exercise]
init() {
//navigationBarBackButton color will change//
UINavigationBar.appearance().tintColor = .purple
// you can also set backgroundColor//
UINavigationBar.appearance().backgroundColor = .white
}
var body: some View {
NavigationView {
List(self.exercises.identified(by: \.number)) {exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
.navigationBarTitle(Text("Exercises"))
}
}
}

How to fix UISearchBar returning NSRangeException when clear button is clicked? (FIXED!!!)

I have implemented a UISearchBar in my app that is crashing when I hit the clear button and while there's one item found. It's like I type in some character, the app searches and display 1 item, but I when I clear the search, it crashes.
I searched stackoverflow and I am aware that the problem is with the array that holds the search items cause when I hit the clear button the array becomes empty and the tableview index path.row can't be displayed.
Also, if the search returns no item and I hit the clear button I get a similar error message buy this time saying the I got an empty array.
The app stops here:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
The problem is that I simple don't know what to do!!!
Here is the error:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
And here is my code::
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
isFiltered = NO;
} else {
isFiltered = YES;
filteredCodigos = [[NSMutableArray alloc]init];
for (NSDictionary *item in values) {
NSString *string = [item objectForKey:#"NAME"];
NSRange stringRange = [string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (stringRange.location != NSNotFound) {
[filteredCodigos addObject:item];
}
}
}
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self.Pesquisa resignFirstResponder];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (isFiltered) {
return [filteredCodigos count];
}
return values.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDictionary *itemAtIndex =(NSDictionary *)[values objectAtIndex:indexPath.row];
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
if (!isFiltered) {
cell.textLabel.text = [itemAtIndex objectForKey:#"SYMBOL"];
cell.detailTextLabel.font = [UIFont systemFontOfSize:10];
cell.detailTextLabel.text = [itemAtIndex objectForKey:#"NAME"];
} else {
cell.textLabel.text = [itemAtIndice objectForKey:#"SYMBOL"];
cell.detailTextLabel.font = [UIFont systemFontOfSize:10];
cell.detailTextLabel.text = [itemAtIndice objectForKey:#"NAME"];
}
return cell;
}
filteredCodigos is declared outside of searchBar:textDidChange: and is used in multiple places but is assigned to in searchBar:textDidChange:. Most likely, some other code is trying to access members of filteredCodigos which is unassigned or empty. Enabling exception breakpoints will help you track it down.
As a side note. You might look at NSPredicate to filter your items instead of the for loop.
Finally managed to fix this issue.
I just replaced indexPath.row for lastObject at the line that was giving me the error:
So, before:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
And after:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos lastObject];

AVAudioPlayer Notification issue

So I'm almost done with my app and I've hit a wall and cannot get around this final problem.
I basically have 2 view's. A main page and the game play screen.
On the first play the game works fine, but when i leave the main screen and then return to the game screen all the sounds are duplicating and firing the the playerItemDidReachEnd early (because I'm guessing there are 2 instances of it, but it cannot seem to get the player to stop this. Here is the basic code causing this. Any help would go a long way, thanks. I'm not sure if my issue is i'm creating multiple instances of View2 in View1 or if I'm creating multiple player objects in view2 thus duplicating the notification.
I know there is a lot going on in my - (void)playerItemDidReachEnd:(NSNotification *)notification, but it works fine on the first load of the page, its only when I click "go back to view1" and then go back in to View2 that the issue happens.
View1ViewController.h
----------------------
#import "(i know here are arrows here, but can't make them show)UIKit/UIKit.h>
#import "ApplicationViewController.h"
#interface MonsterSpellViewController : UIViewController {
}
-(IBAction)showView1;
View2ViewController.m
----------------------
-(IBAction)showView2{
ApplicationViewController *view2 = [[ApplicationViewController alloc]initWithNibName:#"ApplicationViewController" bundle:nil];
view2.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:view2 animated:YES];
}
View2ViewController.h
------------------------
#import "(i know here are arrows here, but can't make them show)UIKit/UIKit.h>
#import "(i know here are arrows here, but can't make them show)AVFoundation/AVFoundation.h>
#class AVAudioPlayer;
#interface ApplicationViewController : UIViewController{
AVAudioPlayer *avPlayer;
}
View2ViewController.m
-------------------------
#import "View2ViewController.h"
#synthesize avPlayer;
-(AVAudioPlayer *)avPlayer {
if(!avPlayer) avPlayer = [[AVAudioPlayer alloc]init];
return avPlayer;
}
-(void) viewDidLoad
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:avPlayer];
}
-(IBAction)playSoundTest
{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/monster3.mp3", [[NSBundle mainBundle] resourcePath]]];
self.avPlayer = [AVPlayer playerWithURL:url];
[self.avPlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
//[player seekToTime:kCMTimeZero];
if (playEscape == YES) {
[self btnEscapeSound];
playEscape = NO;
}
if ((startButton.hidden == NO) && (letterCount != -1) && (playFinal == YES))
{
[self btnFinalSound];
playFinal = NO;
playEscape = YES;
}
NSLog(#"Player Check accessed");
if (letterCount == 3) {
if (Winner == letterCount) {
//moveNextSound = YES;
if (intLoopCount < 104)
{
if (intLoopCount<104) {
[self btnStartOver:intLoopCount];
playFinal = NO;
//intLoopCount++;
}
if (intLoopCount==104) {
startButton.hidden=NO;
playFinal = YES;
}
}
}
}
if (letterCount == 4) {
if (Winner == letterCount) {
//moveNextSound = YES;
if (intLoopCount < 105)
{
[self btnStartOver:intLoopCount];
//intLoopCount++;
if (intLoopCount==105) {
startButton.hidden=NO;
playFinal = YES;
}
}
}
}
}
}
-(IBAction)goBack:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
Try adding [view2 release]; after [self presentModalViewController:view2 animated:YES];

Resources