Dailycode.info

Short solution for short problems

iOS: Using multiple storyboards within a navigation controller.

I had a big story board file and I wanted to start to split it up in multiple storyboards containing views with shared functionality. First I found out how to open a different storyboard modally. But since the application uses a navigation controller at certain points, I also wanted to keep the navigation when opening some other storyboards. 

So iOS makes it really simple:

First instantiate the storyboard you want to navigate to (bundle can be nil if the story board is in the same bundle):

UIStoryboard * planningSB = [UIStoryboardstoryboardWithName:@"PlanningStoryboard"bundle:nil];

Then instantiate the initial view controller:

UIViewController * planningVC = [planningSB instantiateInitialViewController];

And last, just push this view controller into the view controllers collection of the current navigation controller.

[self.navigationControllerpushViewController:planningVC animated:YES];

Now the View controller of the second storyboard is loaded in the navigation controller. When pushed on the back arrow on the top, it will simply go back to the previous view controller and the second story board will be deallocated when the reference to its initial view controller is released.

Next is another example where I change the transition style:

UIStoryboard * planningSB = [UIStoryboardstoryboardWithName:@"PlanningStoryboard"bundle:nil];

UIViewController * planningVC = [planningSB instantiateInitialViewController];

 

[UIView transitionWithView:self.view duration:0.8 options:UIViewAnimationOptionTransitionCrossDissolve

                        animations:^{

                            [self.navigationController pushViewController:planningVC animated:NO];

                        }

                        completion:NULL];

 

 In my case I had a camera view that could be called from several views, I put this on a new storyboard and this works great. Since the camera view was also pointing to the search order view, I had to put the search order view also on a separate storyboard. Again my main story board got simpler.

So have a main story board, and separate as much as you can onto separate storyboards. I made a general class StoryBoardNavigation where I centralized all functions to call child storyboards.

Here is an example of this:

This function navigates to the storyboard called OrderLookupStoryboard and opens the view in start position.

+(void)NavigateToOrderLookupFrom:(UIViewController*)vc {UIStoryboard* sb =[UIStoryboard storyboardWithName:@"OrderLookupStoryboard" bundle:nil];UIViewController* vcTo =[sb instantiateInitialViewController];[UIView transitionWithView:vc.view duration:0.8 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{[vc.navigationController pushViewController:vcTo animated:NO];} completion:NULL];}

This function passes some parameters to the storyboard.

+(void)NavigateToCameraFrom:(UIViewController*)vc WithSelectedZone:(int)selectedZone {UIStoryboard* sb =[UIStoryboard storyboardWithName:@"CameraStoryboard" bundle:nil];MediaCapture* vcTo =[sb instantiateInitialViewController]; vcTo.selectedZone = selectedZone; vcTo.zoneSet = YES;[UIView transitionWithView:vc.view duration:0.8 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{[vc.navigationController pushViewController:vcTo animated:NO];} completion:NULL];}

This function opens the view in module transition style:

+(void)NavigateToSignatureFrom:(UIViewController*)vc withSignee:(NSString*)Signee{UIStoryboard* sb =[UIStoryboard storyboardWithName:@"SignatureStoryboard" bundle:nil];UIViewController* vcTo =[sb instantiateInitialViewController];((SignatureVC*) vcTo).Signee=Signee;[vcTo setModalTransitionStyle:UIModalTransitionStylePartialCurl];[vc presentViewController:vcTo animated:YES completion:nil]; 

} 

 

 

 

 


iOS: Change Navigation Item text inside a Tab Bar Controller

I have an application that uses a navigation controller. After a login screen it navigates to a tab bar controller. The problem was the when tab bars where pressed, the navigation item text was not changed. It show the navigation item text that was set on the tab bar controller.

 

So the way to solve this was to implement a custom UITabBarController. Assign this to your TabBarController as class. Then in the implementation of the custom tab bar controller, you can change the navigation item text according to the tab bar item that was chosen:

- (void)viewDidLoad

{

    [superviewDidLoad];

// Do any additional setup after loading the view.

    self.navigationItem.title = [self.tabBar.items[0] title];

}

 

- (void)didReceiveMemoryWarning

{

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

- (void) tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item

{

    self.navigationItem.title = item.title;

}


Horizontal topnavigation with MVVM and WPF

 

When I was trying to set up a nice framework project that could handle my initial small media management project, I bumped into several designed issues. It was not so easy to find solutions, since I had a hard time looking for the correct Google words to get the info I needed.

The small project is to become a media database where you can insert your media, control it and even manage lend outs. I wanted it to have a top navigation bar and a side navigation. This article is about the top navigation. I’m implementing the MVVM design pattern, that’s what makes it a little more difficult and that’s exactly why I’m posting now.

I made a usercontrol called TopBarButton, which should be used to do the top navigation. Then I made a topcommandview model which exposes the properties the buttons will need to bind to.

This class looks like this:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows.Input;

 

namespace MyMediaControl.ViewModel

{

    /// <summary>

    /// Represents an actionable item displayed by a View.

    /// </summary>

    public class TopCommandViewModel : ViewModelBase

    {

        private string _imageSource;

 

        public string ImageSource

        {

            get { return _imageSource; }

            set { _imageSource = value; }

        }

 

 

        public TopCommandViewModel(string displayName, ICommand command, string imageSource)

        {

            if (command == null)

                throw new ArgumentNullException("command");

 

            base.DisplayName = displayName;

            this.Command = command;

            this._imageSource = imageSource;

        }

 

        public ICommand Command { get; private set; }

    }

}

 

The image source property is to show an image on my button.

Last I need to create a collection in my main window view and bind them to the top navigation bar.

In my main window view model I create a read only collection of TopCommendViewModel.

/// <summary> 

/// Returns a read-only list of commands  

/// that the UI can display and execute.

/// </summary>

public ReadOnlyCollection<TopCommandViewModel> TopCommands

{

    get

    {

        if (_topCommands == null)

        {

            List<TopCommandViewModel> cmds = this.CreateTopCommands();

            _topCommands = new ReadOnlyCollection<TopCommandViewModel>(cmds);

        }

        return _topCommands;

    }

}

 

Here I create the TopCommandViewModel list and you can see I pass 3 parameters to it. First the title of the button coming from a resource file called Strings, second the function to execute and third the image path for the button.

 

List<TopCommandViewModel> CreateTopCommands()

{

    return new List<TopCommandViewModel>

    {

        new TopCommandViewModel(

            Strings.MainWindowViewModel_Command_OpenAudio,

            new RelayCommand(param => this.OpenAudioCommands()),"/Images/audio_icon_120.gif"),

 

        new TopCommandViewModel(

            Strings.MainWindowViewModel_Command_OpenVideo,

            new RelayCommand(param => this.OpenVideoCommands()),"/Images/movie_icon_120.gif"),

        new TopCommandViewModel(

            Strings.MainWindowViewModel_Command_OpenBook,

            new RelayCommand(param => this.OpenBookCommands()),"/Images/books_icon_120.gif")

    };

}

 

When this is done I still need to do the binding in my View. For this we need to work in 2 places. First place is a resource file which is linked to my main window. XAML and next I will add a content presenter to the XAML of my main window.

Here is the code for the data template which can be found in the resource file, this is the code as I where I started with, later I will add something extra to show you the result:

<DataTemplate x:Key="TopCommandsTemplate" >

        <ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="0" >

            <ItemsControl.ItemTemplate>

                <DataTemplate>

                    <my:TopNavButton Text="{Binding Path=DisplayName}" Image="{Binding Path=ImageSource}"

                    ImageWidth="70" ImageHeight="70" Margin="5" ></my:TopNavButton>

                </DataTemplate>

            </ItemsControl.ItemTemplate>

        </ItemsControl>

    </DataTemplate>

 

Last we define the place where we want the navigation buttons to show up:

<Canvas Height="100" Name="spTopNav"  Width="Auto" MinWidth="400" Style="{StaticResource MainNAVStyle}" Margin="0">

    <ContentPresenter Canvas.Left="0" Canvas.Top="0"

        Content="{Binding Path=TopCommands}"

    ContentTemplate="{StaticResource TopCommandsTemplate}"

    HorizontalAlignment="Left" VerticalAlignment="Stretch"

    />

</Canvas>

 

Now here how this all looks like in design time view:

TopNavBarDesign.jpg

So at this time when I run the project, it looks like this:

TopNavBarNOK.jpg

If you look closely, you will discover that just below the first top navigation button, the second one is rendered but not visible or usable for the user. I tried to find a solution and had to do a lot of google searches until I ended up with the solution, using the items panel template.

So I added this to the data template of my topcommandsbutton template:

<DataTemplate x:Key="TopCommandsTemplate" >

    <ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="0" >

        <ItemsControl.ItemTemplate>

            <DataTemplate>

                <my:TopNavButton Text="{Binding Path=DisplayName}" Image="{Binding Path=ImageSource}"

                ImageWidth="70" ImageHeight="70" Margin="5" ></my:TopNavButton>

            </DataTemplate>

        </ItemsControl.ItemTemplate>

        <ItemsControl.ItemsPanel>

            <ItemsPanelTemplate>

                <StackPanel Orientation="Horizontal"/>

            </ItemsPanelTemplate>

        </ItemsControl.ItemsPanel>

    </ItemsControl>

</DataTemplate>

 

Now it will show the items in a stackpanel which is oriented horizontally. Now it looks like this:

TopNavBarOK.jpg