SwiftUI Buttons and their tappable areas shifted away and doesn't cover anymore - button

I have the problems with views and especially buttons as they can be tapped (but it applies to all views) that they tappable (focus area) shifted a bit from rendered views.
Layout stays ok but if you want to tap at the button its tappable area is shifted downward and to the right. So instead of clicking at the button you click a bit downa and right to it. Otherwise there is no action executed.
The best it can be seen on this view from Debug view hierarchy. It happend after returning from modal presentation. But I cannot see any clue in code way that can happen. We on which it happens seems to be no different from other views that work absolutly right.
I can see that wrapping VStack inside ScrollView breaks this view, but it doesn't happan on other similar views.
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
Group {
contentView
contentView
contentView
contentView
contentView
contentView
contentView
contentView
}
contentView
contentView
contentView
contentView
}
.padding(.horizontal)
}
.navigationViewStyle(.stack)
}

Ok I found it. The problem was that content of this view depends on #Published property like shoulDisplayView1Or2. And depending whether it was true or false it displayed view1 or view2.
Moreover this property was set in the same time when presented modal view (sheet) was dismissing. Like after some action do to things 1. dismiss modal and set new value of shouldDisplayView1Or2. And this sheet dismissal and adjuting view1 or view2 based on shouldDisplayView1Or2 flag caused that this buttons rendered areas and their tappable areas become shifted away.
What fixed this issue was addition of DispatchQueue.main in Combine subscription or DispatchQueue.main.async { } in regular code in place where this flag shouldDisplayView1Or2 was setting. This way I suppose dismissing comes first and adjusting view1 or views with its rendering second, and overall layout wast rendered correctly with tappable areas on its place.

Related

NavigationController & hidesBarsOnSwipe with CollectionView subview

I'm pretty new to iOS development and I'm having some trouble with navigation controller and a collection view as a Subview.
Ive started my project with a single view application and embedded in a Navigation controller (The Navigation controller root is my ViewController).
Inside my view controller i've added a Collection view with a custom cell (it doesn't take the whole screen).
when I run my application everything works fine.
when I tried to set the method
navigationController?.hidesBarsOnSwipe = true
nothing happens inside my Collection view even though I'm scrolling, but if I swipe within the View controller and not the Collection view the method works and the Navigation bar gets hidden just fine.
I want the method to work when I swipe inside the Collection view.
Thank...
If your collection view top is set to the top layout guide top then the view behind is has never scrolled, i.e. your view isn't scrolling so the navigation bar is not hiding.
Try setting your collection view top to the "Top Layout Guide.Top". Try changing this to "Superview.Top".

CoordinatorLayout with different Toolbar behaviour

I'm having difficulty in implementing CoordinatorLayout as how to implement the Toolbar if some of my Fragments have a different Toolbar behaviour. Say, that I have 5 fragments that would be shown in just one Activity (one fragment at a time). 2 of them would have a auto-hide Toolbar when scrolled, 1 with a simple Toolbar that's always showing even when scrolled, and 2 having Toolbar with ImageView inside AppBarLayout for parallax effect.
This link only cover the auto-hide part, but not the parallax with image.
Some solutions that I could think of :
Have one AppBarLayout with Toolbar and ImageView in Activity. So if it displays a fragment that doesn't need the parallax effect, just set the ImageView's visibility to GONE. But is it okay to do this? Because I got the feeling that it's not an appropiate solution.
Define CoordinatorLayout and Toolbar in each fragments' layout. But then I have to call setSupportActionBar everytime I'm displaying my fragment, when some of them actually have the same Toolbar.
Which is the best approach? Or maybe there is a better one than those two?
UPDATE
So, I ended up with number 2. I just add toolbars to each fragments' xml just like usual, nothing special. And in my BaseActivity I create a method to set the toolbar as action bar with some default configuration, so I won't have to duplicate the syntax to each of my fragments. Here's the method:
public void setToolbar(Toolbar toolbar, String title){
if(toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(title != null);
if (title != null) setActionBarTitle(title);
}
}

UI Layout, fragments and different content

I'm studying fragments and "Multiple devices support". Depending on device type, orientation and dimension, it's possible to define multiple layout using fragments and re-using written code. During the develop of an app, I wrote down my desired UI for tablet devices, as described in the following screenshot:
The activity contains two fragments and displays TAB menu navigation. Every TAB menu navigation contains different menu entry (listview).
When clicking on a menu's item on fragment 1, I need to refresh the fragment number 2.
Fragment 2 is composed by a presentation and, below, a listview or another presentation.
Every menu's item could have different layout:
1-Presentation, image, another presentation
2-No presentation, listview
3-Presentation, listview
4-etc.
Studying examples (samples) provided with google-sdk, fragment 2 have always the same layout. How it's possible to tell fragment 2 to load different layout depending on menu's item clicked?
My answer is: I need a fragment class for every different layout. When the user click on an item of fragment 1, the fragment manager should replace and commit the correct fragment. Is this answer correct?
All fragment logic will be on my activity, replacing the correct fragment depending on item selected (position and category); simple ex:
#Override
public void onItemSelected(int category, int position) {
if (position==0){
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frag, new FirstActionFragment(), "FirstMenuClicked");
ft.commit();
}
else {
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frag, new SecondActionFragment(), "secondMenuClicked");
ft.commit();
}
}
Is my layout idea improvable? Should I change something on my design to correctly implement fragmentation?
Here is the solution of your problem
https://github.com/theomega/ActivatedStateDemo

Not able to drag scrollview object in interface builder

I'm using XCode 4.6 and interface builder. I've got a UIViewController in interface builder, and a UIScrollView on top within the UIViewController. The scroll view completely spans the view controller (actually, it's taller than the view controller, it has height that is below the bottom of the view controller). This has been working for sometime, but I just ran into a problem. Somehow, I can no longer grasp the scroll view to drag it and reposition it. I click on the scroll view in IB or within the outline but the "hand" icon will not appear to enable movement and repositioning of the scroll view. Ideas?
I'd really rather not re-create all the detailed views within the scroll view. Perhaps this is why some people have a negative attitude about IB? Loosing work because of silly problems that stop you dead.
Thanks,
Chris.
I think I've solved this now. I believe there was supposed to be three layers: (from top to bottom; top towards user) scroll view, view (), and view controller. Somehow I lost the view in the middle () and this was not letting me resize the scroll view.

Substitution of detail view controller does not cause viewWillAppear to be called

I'm porting my iPhone app to iPad. On iPhone I select row in the table, and after that the next view controller is pushed to the top of navigationController (now navigation is performed on the left part of split view controller). For iPad i modified the code this way:
if (deviceIsIPad())
{
UISplitViewController *svc = (UISplitViewController *)[self findNearestParentOfClass:[UISplitViewController class]];
svc.viewControllers = [NSArray arrayWithObjects:[svc.viewControllers objectAtIndex:0],
nextViewController,
nil];
}
else
[self.navigationController pushViewController:nextViewController animated:YES];
There are no problem at iPhone code (when controller is pushed to navigation controller), but on iPad viewWillAppear: is not called (viewDidLoad is called however), while I have a reason to perform some customization right in viewWillAppear:. Why is it not called, and what should I do to force it to be called?
Much thanks in advance!
Not exactly sure what you're trying to do here but simply initializing a splitview controller and adding controllers to it does not force views to appear. You have to add the splitview controller's views to the window.
Here is the code from the Xcode Splitview template's app delegate's applicationDidFinishLaunching:
splitViewController = [[UISplitViewController alloc] init];
splitViewController.viewControllers = [NSArray arrayWithObjects:navigationController, detailViewController, nil];
splitViewController.delegate = detailViewController;
NSLog(#"master=%#",splitViewController.viewControllers);
// Add the split view controller's view to the window and display.
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
The views in the navigation controller appear because it is already attached to the window and displaying the view of one of its controlled controllers.
Edit:
From Comments:
All initialization code you are quoted
here is already performed. Now, let's
assume one have a table on the left
controller, then he select another row
there, and want to replace right
controller with another one.
splitViewController.view is added on
the window фдкуфвн, because some GUI
elements initialized in viewDidLoad,
are properly presented on view
It sounds like your problem arises because the detail (right-side) view of a splitview controller is always visible i.e. it only appears i.e calls viewWillAppear, once immediately after first being loaded. There is no point at which the detail side has no view present. I'm not sure what entirely swapping out viewControllers of the splitview will do.
If you want to change the detail view on the fly. You need to put a navigation controller in the right side and then push and pop view-controllers in that nav in response to events in the right side controller.
Look at how the iPad iPod app works. You have a leftside view of playlist and on the right side, a list of all the songs in the playlist. Selecting a song pushes a song detail view on top the list of songs.

Resources