Android Fragment transaction: FragmentManager and Backstack

Fragments are useful when we want to support multiple screen size. To manage fragments we need a
FragmentManager that help us to handle trasaction between fragments.  With transaction we mean a sequence of steps to add, replace or remove fragments. In the last post we showed how to support multiple screen size and orientation using fragments. Now we want to go a bit further.
In Android there are two different methods to create fragment:

  • static method
  • dynamic method

Static method is when we “write” directly our fragment in XML file. This is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:orientation="horizontal" >
        <fragment android:id="@+id/listFragment"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              class="com.survivingwithandroid.fragment.LinkListFragment"
              android:layout_weight="2"/>
</LinearLayout>

In this case our layout isn’t dynamic because we can’t manage the fragment at runtime. So if we want to make our layout dynamic (and this happen very often) we need to do it in another way. We have to use FrameLayout. With FrameLayout we can handle fragments as we need at runtime, but to do it we need a manager, in other words a component that can handle fragments. This is FragmentManager. This component can add, replace and remove fragments at runtime. The layout above becomes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
   
    <FrameLayout
        android:id="@+id/listFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
   
</RelativeLayout>

So now we have all the freedom to “inject” in the FrameLayout our fragments.

FragmentManager

As we said before FragmentManager is the key component. Using FragmentManager we can discover (find) fragment inside our layout using findFragmentById or findFragmentByTag. While the first method is very simple and we use the common android id to discover the component, the second method (that uses tag) is unsual. A tag in a fragment is simply a “name” we give to the fragment so that we can find it later using that name. We are more interested in some other methods.

All the operation that are made by the FragmentManager happens inside a “transaction” like in a database operation. First, we can get the FragmentManger using the Activity method getFragmentManager(). Once we have the reference to this component we have to start the transaction in this way:

1
2
3
4
5
6
7
8
9
FragmentManager fm = getFragmentManager();
// Transaction start
FragmentTransaction ft = fm.beginTransaction();
.......
// Transaction commint
ft.commit();

At the end when we finished and we are ready to show our fragment we have to call the commit method that marks the end of the transaction. For example, if we remember the example we showed in the last post, and using a FrameLayout we can “insert” the link list in this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MainActivity extends Activity implements ChangeLinkListener{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        
        LinkListFragment llf = new LinkListFragment();
        ft.replace(R.id.listFragment, llf);
        ft.commit();
    }
  ...
}

But…What kind of operation we can perform inside the transaction?…Well we can:

  • add a new fragment
  • replace an existing fragment
  • remove a fragment

If we remember the example we used last time every time an user clicks on a link the interface method onLinkChange is called. So in this method we want to show how to perform the operation listed above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if (findViewById(R.id.fragPage) != null) {
    WebViewFragment wvf = (WebViewFragment) getFragmentManager().findFragmentById(R.id.fragPage);
   
// Part 1: Tablet and so on
    if (wvf == null) {
        System.out.println("Dual fragment - 1");
        wvf = new WebViewFragment();
        wvf.init(linkData.getLink());
        // We are in dual fragment (Tablet and so on)
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        //wvf.updateUrl(link);
        ft.add(R.id.fragPage, wvf);
        ft.commit();
        
    }
    else {
     Log.d("SwA", "Dual Fragment update");
     wvf = new WebViewFragment();
      wvf.init(linkData.getLink());
      FragmentManager fm = getFragmentManager();
     FragmentTransaction ft = fm.beginTransaction();           
     ft.replace(R.id.fragPage, wvf);
     ft.commit();
     
     //wvf.updateUrl(linkData.getLink());
    }
}
else {
    Log.d("SwA", "replace");
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    WebViewFragment wvf =  new WebViewFragment();
    wvf.init(linkData.getLink());
    ft.replace(R.id.listFragment, wvf);
    ft.commit();
}

If you compare this piece of code with the last example in the previous post you notice some differences. First in the green part we don’t start an activity anymore when user clicks on a link but we simply replace the FrameLayout with a fragment showing the web page. More over, in the yellow part we don’t update the current fragment inside the FrameLayout but we create a new fragment and we replace the existing fragment with the one just created. The app behaviour is always the same but we obtained this behaviour in a different way, using dynamic fragments inside our layout.

If you run the app and start using it you can notice a “wired” behaviour when you press back button. We’d expect that the back button would bring us to the last web page visited but it isn’t like we supposed. When you press back button you come to the home page.

android_fragment_tutorial1android_fragment_tutorial2android_fragment_tutorial3

Why?

Fragment Backstack

Well the behaviour described above is normal because the back button acts at activity level not at the fragment level. So our activity is the same while we replace fragments as the user interacts with the app. In this way when we tap on the back button we select the first activity on the activity stack, in our case the home. We don’t want this behaviour but we want that when we click on the back button we go back in the fragments stack. We can achieve it adding the fragment to the backstack. We do it in this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Override
public void onLinkChange(LinkData linkData) {       
    System.out.println("Listener");
    // Here we detect if there's dual fragment
    if (findViewById(R.id.fragPage) != null) {
        WebViewFragment wvf = (WebViewFragment) getFragmentManager().findFragmentById(R.id.fragPage);
       
        if (wvf == null) {
            System.out.println("Dual fragment - 1");
            wvf = new WebViewFragment();
            wvf.init(linkData.getLink());
            // We are in dual fragment (Tablet and so on)
            FragmentManager fm = getFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            //wvf.updateUrl(link);
            ft.add(R.id.fragPage, wvf);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            // Add to backstack
            ft.addToBackStack(linkData.getName());
            ft.commit();
            
        }
        else {
         Log.d("SwA", "Dual Fragment update");
         wvf = new WebViewFragment();
          wvf.init(linkData.getLink());
          FragmentManager fm = getFragmentManager();
         FragmentTransaction ft = fm.beginTransaction();           
         ft.replace(R.id.fragPage, wvf);
         ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
          // Add to backstack
          ft.addToBackStack(linkData.getName());
          ft.commit();
         
         //wvf.updateUrl(linkData.getLink());
        }
    }
    else {
        /*
        System.out.println("Start Activity");
        Intent i = new Intent(this, WebViewActivity.class);
        i.putExtra("link", link);
        startActivity(i);
        */
           Log.d("SwA", "replace");
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        WebViewFragment wvf =  new WebViewFragment();
        wvf.init(linkData.getLink());
        
        ft.addToBackStack(linkData.getName());
        ft.replace(R.id.listFragment, wvf);
        ft.commit();
    }
    
}

We use the addToBackStack method of the FragmentTrasaction and we add every fragment to the backstack. In this way when we tap on the back button we have the correct behaviour.
– See more at: http://www.survivingwithandroid.com/2013/04/android-fragment-transaction.html#sthash.chIXV9Ie.dpuf

Part 2 – Managing Fragments

To help with managing Fragments, Android provides the FragmentManager class. Each Activity has an instance of Android.App.FragmentManager that will find or dynamically change its Fragments. Each set of these changes is known as a transaction, and is performed by using one of the APIs contained in the class Android.App.FragmentTransation, which is managed by the FragmentManager. An Activity may start a transaction like this:

FragmentTransaction fragmentTx = this.FragmentManager.BeginTransaction();

These changes to the Fragments are performed in the FragmentTransaction instance by using methods such as Add(), Remove(), and Replace(). The changes are then applied by using Commit(). The changes in a transaction are not performed immediately. Instead, they are scheduled to run on the Activity’s UI thread as soon as possible.

The following example shows how to add a Fragment to an existing container:

// Create a new fragment and a transaction.
FragmentTransaction fragmentTx = this.FragmentManager.BeginTransaction();
DetailsFragment aDifferentDetailsFrag = new DetailsFragment();

// The fragment will have the ID of Resource.Id.fragment_container.
fragmentTx.Add(Resource.Id.fragment_container, aDifferentDetailsFrag);

// Commit the transaction.
fragmentTx.Commit();

If a transaction is committed after Activity.OnSaveInstanceState() is called, an exception will be thrown. This happens because when the Activity saves its state, Android also saves the state of any hosted Fragments. If any Fragment transactions are committed after this point, the state of these transactions will be lost when the Activity is restored.

It’s possible to save the Fragment transactions to the Activity’s back stack by making a call to FragmentTransaction.AddToBackStack(). This allows the user to navigate backwards through Fragment changes when the Back button is pressed. Without a call to this method, Fragments that are removed will be destroyed and will be unavailable if the user navigates back through the Activity.

The following example shows how to use the AddToBackStack method of a FragmentTransaction to replace one Fragment, while preserving the state of the first Fragment on the back stack:

// Create a new fragment and a transaction.
FragmentTransaction fragmentTx = this.FragmentManager.BeginTransaction();
DetailsFragment aDifferentDetailsFrag = new DetailsFragment();

// Replace the fragment that is in the View fragment_container (if applicable).
fragmentTx.Replace(Resource.Id.fragment_container, aDifferentDetailsFrag);

// Add the transaction to the back stack.
fragmentTx.AddToBackStack(null);

// Commit the transaction.
fragmentTx.Commit();

Communicating with Fragments

The FragmentManager knows about all of the Fragments that are attached to an Activity and provides two methods to help find these Fragments:

  • FindFragmentById – This method will find a Fragment by using the ID that was specified in the layout file or the container ID when the Fragment was added as part of a transaction.
  • FindFragmentByTag – This method is used to find a Fragment that has a tag that was provided in the layout file or that was added in a transaction.

Both Fragments and Activities reference the FragmentManager, so the same techniques are used to communicate back and forth between them. An application may find a reference Fragment by using one of these two methods, cast that reference to the appropriate type, and then directly call methods on the Fragment. The following snippet provides an example:

It is also possible for the Activity to use the FragmentManager to find Fragments:

var emailList = FragmentManager.FindFragmentById<EmailListFragment>(Resource.Id.email_list_fragment);
emailList.SomeCustomMethod(parameter1, parameter2);

RE: Walkthrough – Creating a tabbed UI with TabHost

This article will walk through creating a tabbed UI in Xamarin.Android using the TabHost API. This is an older API that is available in all versions of Android. This example will create an application with three tabs, with the logic for each tab being encapsulated in an Activity. The following screenshot is an example of the application that we will create:

Creating the Application

    1. Download and unzip the project . This project serves as the starting point for our application and contains some images. This is a Xamarin.Android Application project that you would get from File > New > New Solution and accept the Android Application template. If you examine this project, you will see that we’ve already created the drawable resources for the tab icons.
    2. First let’s update the layout file Resources/Layout/Main.axml that will host the tabs. Edit file Resources/Layout/Main.axml file and insert the following XML:
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@android:id/tabhost"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent">
    <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dp">
        <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
        <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:padding="5dp" />
    </LinearLayout>
</TabHost>

The following screenshot shows the layout in the Xamarin Designer:

The TabHost must have two child views inside it: a TabWidget and a FrameLayout. To position the TabWidget and FrameLayout vertically inside the TabHost, a LinearLayout is used. The FrameLayout is where the content for each tab goes, which is empty because the TabHost will automatically embed each Activity at runtime.

There are several rules that must be observed when it comes to creating the layout for tabbed user interfaces:

  • The TabHost must have the id @android:id/tabhost.
  • The TabWidget must have the id @android:id/tabs.
  • The FrameLayout must have the id @android:id/tabcontent.
  • TabHost requires any activity it manages to inherit from TabActivity. Therefore, it is important to subclass TabActivity here – a regular Activity will not work.

    Edit the file MainActivity.cs so that the class MainActivity subclasses TabActivity as shown in the following code snippet:

[Activity (Label = "@string/app_name", MainLauncher = true, Icon="@drawable/ic_launcher")]
public class MainActivity : TabActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);
    }
}
  • Create four separate Activity classes in your project: MyScheduleActivity, SessionsActivity, SpeakersActivity, and WhatsOnActivity. Each activity will make up the UI of a tab. For now these Activities will be a stub that displays a TextView with a simple message. Edit the code in each activity to contain the following OnCreate implementation:
[Activity]
public class MyScheduleActivity : Activity
{
    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);
        TextView textview = new TextView (this);
        textview.Text = "This is the My Schedule tab";
        SetContentView (textview);
    }
}

Notice that the above code doesn’t use a layout file. It just creates a TextView with some text, and sets that TextView as the content view. Duplicate this for each of the remaining three activities.

  • Next we will assign the icons to each tab. Each tab requires two icons – one for the selected state and one for the unselected state. An example of these two different icons can be seen in the following two images:

  

The necessary icons for this application have already been added to the sample project.

We will assign the drawable resources to the icon tabs by defining a State-List Drawable. State-list drawables are a special drawable resources that are defined in XML and allow you to specify different images that are specific to that item’s state. In this example there is one image that is used when a tab is selected, and another that is used when the tab is not selected. To save you time, the necessary state-list drawables have been added to the project. The following table shows the files and the XML they contain:

State-List Drawable File XML
ic_tab_my_schedule.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_tab_whats_on_selected"
          android:state_selected="true"/>
    <item android:drawable="@drawable/ic_tab_whats_on_unselected"/>
</selector>
ic_tab_sessions.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_tab_sessions_selected"
          android:state_selected="true"/>
    <item android:drawable="@drawable/ic_tab_sessions_unselected"/>
</selector>
ic_tab_speakers.xml
<?xml version="1.0" encoding="utf-8"?>
                <selector xmlns:android="http://schemas.android.com/apk/res/android">
                    <item android:drawable="@drawable/ic_tab_speakers_selected"
                          android:state_selected="true"/>
                    <item android:drawable="@drawable/ic_tab_speakers_unselected"/>
                </selector>
ic_tab_whats_on.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_tab_whats_on_selected"
          android:state_selected="true"/>
    <item android:drawable="@drawable/ic_tab_whats_on_unselected"/>
</selector>
  • Tabs are added to the TabHost programmatically, which is a very repetitive task. To help with this, add the following method to the class MainActivity:
private void CreateTab(Type activityType, string tag, string label, int drawableId )
{
    var intent = new Intent(this, activityType);
    intent.AddFlags(ActivityFlags.NewTask);

    var spec = TabHost.NewTabSpec(tag);
    var drawableIcon = Resources.GetDrawable(drawableId);
    spec.SetIndicator(label, drawableIcon);
    spec.SetContent(intent);

    TabHost.AddTab(spec);
}

Each tab in the TabHost is represented by an instance of the of the TabHost.TabSpec class. This instance contains the meta-data necessary to render the tab, specifically:

  • Text and Icon – To be displayed in the TabWidget.
  • Tab Content – This may be either an Activity or a View and is displayed when the tab is selected.
  • Unique Tag – Each tab must have a unique tag assigned to it.

We must add a TabHost.TabSpec instance for each tab in our application. Lets do that in the next step.

  • Update the method OnCreate in MainActivity so that it resembles the following code:
  1. protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);
    
        CreateTab(typeof(WhatsOnActivity), "whats_on", "What's On", Resource.Drawable.ic_tab_whats_on);
        CreateTab(typeof(SpeakersActivity), "speakers", "Speakers", Resource.Drawable.ic_tab_speakers);
        CreateTab(typeof(SessionsActivity), "sessions", "Sessions", Resource.Drawable.ic_tab_sessions);
        CreateTab(typeof(MyScheduleActivity), "my_schedule", "My Schedule", Resource.Drawable.ic_tab_my_schedule);
    }

  2. Run the application. Your application should look something like the following:

That’s it! We have created a tabbed application which gives the user an easy way navigate to different parts of an application

Summary

This chapter discussed tabbed layouts and guided you through process of creating a tabbed application. The walkthrough demonstrated how to use a TabActivity to inflate a layout file that hosting a TabHost and a TabWidget. The TabHost was then populated with a collection of TabHost.TabSpec objects which would be used by the TabHost at runtime to instantiate the activities that would be used in each tab.

工作笔记 – 数据交互与现任任务

加单更新单等功能都是在内存里记忆数据。当用户点击CONFIRM时,存入本地数据库。 内存里的东西当切出时可能随时会被系统杀掉,但相反它的运行速度是最快的。当用户点击CHECK OUT时,数据才会被发送至远程服务器,以此来减少对服务器的依赖。

TASK:做UI层面上的逻辑以及数据的调用。

选项:

option:其实是主要选项,比如选牛肉还是羊肉炒饭

grouped price:同样一个价格里可以选择任何的东西,比如SUBWAY里加番茄,生菜

addon:这应该叫OPTION,里面是可选但收费的选项

以上是复杂菜系,所有有多选。

简单菜系则没有,可以直接选择点的数量。

Tab Bar Controllers in Storyboards

While Navigation controllers often have the limelight when it comes to Xcode controllers, Tab Bar controllers are great for independent tasks in the same app or for different ways of working with the same model. In this lesson, we’ll take a look at tab bar controllers and how to add them in the storyboard.  For more on implementing them in code see Swift Swift: Using Tab Bar Controllers in Swift.

Creating from the Template

The easiest way to make a tab bar controller is through Xcode’s template. In Xcode, press Command-Shift-N or File>New>Project. Select the tabbed application.
This will give you a window with two tabs installed with two labels each and a tab item on the bottom of each controller. The template tends to make things more complicated instead of less, so it is rarely used.

Creating From A Single View

The most common way to make a tab bar controller is to start from a single view and embed it in a controller. We’ll try an example of this one In Xcode, press Command-Shift-N and select Single View. Make a file named SwiftTabBarEmbed, using Swift as the language and with a Universal device. Once created, go over to the Storyboard. Select the view controller by clicking the view controller icon or title, and select Editor>Embed in>Tab Bar Controller.

Screenshot 2015-01-27 05.38.51

This will turn the single view controller into the first view controller of the tab bar.

Screenshot 2015-01-27 05.40.04

You can add view controllers by dragging out a view controller then control-dragging from the tab bar controller to the new controller. In the popup, select under Relationship Segue the view controllers option.

Screenshot 2015-01-27 06.05.53

A segue appears on the story board. You’ll see a second tab in the tab bar controller.

Screenshot 2015-01-27 06.08.46

Adding More Tabs with System Icons

To configure the tab bar icon, go to the Item icon in the View Controller (not on the tab view controller) we just made and click it. This will bring up in the properties inspector the Tab Bar Item and Bar Item properties. In the Tab Bar Item properties is the System Item drop down. This is where we configure the tab bar button.

Screenshot 2015-01-27 07.08.34

In the System Item menu, Click the drop-down for System Item. you will see a  list of system icons.

Screenshot 2015-01-27 06.24.23

Select Favorites. The Icon changes both on the view controller and the tab bar controller.

Screenshot 2015-01-27 06.29.10
Click the other view controller’s tab bar, and change the system Icon to Recents.
Drag out six more view controllers, so we have a total of eight controllers. Control-drag from the tab bar controller to each new view controller and assign Contacts ,Bookmarks ,Search, Downloads ,and Most Viewed to the controllers, leaving one as a custom item. The tab bar controller should look like this:

Screenshot 2015-01-27 06.41.22

Using More

Set the simulator to an iPhone 6. Build and run. While your icons may be in a  different order, you will get something like this for the tab bar at the bottom of the phone:

Screenshot 2015-01-27 06.43.18

We get an extra tab we did not set up titled More. Tap on the More icon.

Screenshot 2015-01-27 06.47.05

Compact widths cannot handle more than five tabs. If you add more than five tabs, it places a More tab as the fifth tab and makes this table view for you. If you tap the tab in the table’s cell, the tab’s controller will appear.

Without any more code, tab bar controllers let users customize their tab bars. Tab the Edit button, and you get a configuration view:

Screenshot 2015-01-27 06.53.13

Drag one of the icons down to the tab bar. It replaces one tab. You can also drag tabs in the tab bar to change the order. Try getting the tab bar to look like in the above screenshot, then tap Done. Your tab bar now looks like this:

Screenshot 2015-01-27 07.01.21

One of the system icons you can use is a More icon. Be careful when using the More icon in a tab bar. It can cause user confusion between the More tab and your own use for More.

Close the simulator. In the storyboard, delete three view controllers so you get a tab bar like this:

Screenshot 2015-01-27 07.05.10

Since we now have five icons, this will keep off the More icon.

Custom Tab Bar Items

Click on the tab bar for the one custom controller.We can see all the tab bar properties.

Screenshot 2015-01-27 07.08.34

The lower half has bar item properties, which directly control the title and icon for the tab. We can easily change the text. Change the Bar Item Title to Square.

Screenshot 2015-01-27 12.36.47

The title changes on the tab bar:

Screenshot 2015-01-27 12.37.13

If we change a System items’s title, it becomes a custom item, and the icon disappears. Click on the Contacts Icon. Change the title to Pizza. Do the same to change Downloads to Pie. All become squares.

Icon Images

Under Title in the properties inspector,  we have a drop down for Image. For a custom bar item we can supply the icon. Image icons are not like other images. They are monochrome images,  unlike anything else you have ever seen. They are set not by color but by the alpha value , or transparency of the image. You can make any image here any color, but it will show up as a solid tint color if you select an alpha value of 100% and background color if you select 0% alpha. For example I created the following icons in both high and low resolutions:

gradient bar Pizza and Pie Bat items pizza bar icon pizza bar icon@2x pie bar icon pie bar icon@2

Icons are 30 points by 30 points, which means for retina images make the icon a 60 pixel by 60 pixel image and for low resolution images 30 pixel by 30 pixel. You can download them individually by right clicking the images above, and saving them to a folder.  Use these file names:

Screenshot 2015-01-27 07.37.51

You can also download a.zip file Of these here:Tab Bar Assets

For those not familiar with Apple image naming conventions, low resolution images have a file name. Retina Images have @2x appended to that file name. This tells Xcode to know what resolution it is. We have both 60×60 pixel retina and 30×30 pixel standard images. By loading both into Xcode, the system will use the correct one automatically for the device.
In Xcode’s navigator panel, open up images.xassets. Select both gradient bar icon files. Drag them into the center panel in Xcode, which will highlight, and the number 2 will appear next to your cursor. Release the mouse button, and you will see a new collection in the image assets.

Screenshot 2015-01-27 07.47.43

Do the same for the pie bar and pizza bar files Select the pizza bar.png and pizza bar@2x.png files and drag them to the assets manager. Do the same for the pie bar.png and pie bar@2x.png buttons.
Return to the storyboard. On the tab we titled Square,click anywhere on the tab bar.  Select the image drop-down in the tab bar properties and select the gradient bar icon.

Screenshot 2015-01-27 07.56.11

Find the Pizza and Pie tab views on the storyboard, and change them the same way. The Tab bar controller now has three custom icons.

Screenshot 2015-01-27 08.00.29

Build and run with the iPhone 6 simulator, and you will see our three icons, with one highlighted as selected.

Screenshot 2015-01-27 08.02.08