Saturday, May 25, 2013

ActionBar/ActionBarSherlock Tabs

Navigation Tabs:
ActionBar supports built-in Tabs or drop-down lists that you can use to change the Fragment is currently  visible. We are going to work with ActionBarSherlock library so we can have backwards compatibility.

Note 1 :  Either Tabs or drop-down lists but not both in ActionBar.
Note 2 :  Every Tab is associated with one Fragment. To change Fragments by using the Tabs,  perform a FragmentTransaction each time a Tab is selected.

Display Tabs :  



Add Tabs :

You can add Tabs with the addTab() method. The first Tab added is the selected one therefore the visible.
Code is like below :



Implement ActionBar.TabListener :

We 're going to split it into 3 parts :

  1. First part the implementation of the Fragments.
  2. Second part the implementation of ActionBar.TabListener 
  3. Third part is to add the Tabs using the TabListener we created before.
The result we expect is the screenshot below :




1) Fragments 
Fragment class is just a basic Fragment class in which we only inflate the layout :


And the corresponding XML layout :



We repeat this process for Fragment_2.

2) TabListener 
TabListener's implementation is the most difficult part of the work.



Our constructor is  public TabListener(Activity activity, String tag, Class<T> clz)  where activity is the host Activity, tag is the identifier Tag of the fragment and cls the Fragment's class so we can instantiate the fragment.

Callbacks in this Interface will handle the event. Specifically when a Tab is clicked then onTabSelected() will execute the Fragment transaction and add the fragment to the Activity.

In our case the Tab content will fill the activity's layout, so our activity doesn't needs a layout. Each fragment is placed in the default root ViewGroup, which we can refer to with the android.R.id.content ID.

3) MainActivity
Because we have to deal with Fragments our MainActivity  will extend FragmentActivity ( or just Activity for Android 3.0 and up ) but in our case with ActionBarSherlock will extend the SherlockFragmentActivity.





All we are doing here is to get the ActionBar item, and add Tabs with the addTab() method.
We set a TabListener for each Tab by calling the setTabListener().
Also we set the tab's title and/or icon with setText() and/or setIcon().

That's all ! Check all the code and/or fork the project from github here so you can see by yourself how it works. 

Tuesday, May 14, 2013

Simple Fragment Transactions

What we are going to do here is a simple Activity with a button. When we click that button a Fragment Transaction takes place and we add the Fragment's layout.

1. You start a new Project and you are using support library if you target API less than 11. So first add the support lib to the project.

2. In my case I'm extending FragmentActivity ( i'm using minimum sdk version 8  ) or for API 11 and above you can use just Activity.

3.  First we are going to create the Fragment.

We extend Fragment class, inflate Fragment's layout at onCreateView() method and declare an Interface for future communication between Fragment and Activity.
So our code is here :


public class Fragment_A extends Fragment {

protected static final String TAG = "FRAGMENTS_A";
private CallbackInterface listener;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_a_layout, container, false);

        return view; //returns view
    }
 
    // ********** declare INTERFACE ***************** //
 
    public interface CallbackInterface {
    public void onSomethingSelected(int position);
      }      

 
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
     
        // This makes sure that the container activity has implemented the callback interface. If not, it throws an exception
        try {
            listener = (CallbackInterface) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement CallbackInterface");
        }
    }
 
 
}

4. Fragment's layout 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="@color/cool">
    
    <TextView
        android:id="@+id/tv"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Fragment A" />
</LinearLayout>


5. Now we are going to create our Activity :



public class MainActivity extends FragmentActivity  implements CallbackInterface  {

private static final String TAG = "passNumberTAG";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


final Button button = (Button) findViewById(R.id.button_id);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
         
       Fragment_A Frag_A = new Fragment_A();
         
       FragmentManager fm1 = getSupportFragmentManager();
        FragmentTransaction transaction = fm1.beginTransaction();
            
        transaction.add(R.id.fragment_container, Frag_A);
        transaction.commit();
            
        }
    });

}

@Override
public void onSomethingSelected(int position) {
Log.d(TAG, "Give me the result  " + position  );
position = position +1;
Log.d(TAG, "Give me the result  " + position  );

}

}

The part where the Transaction takes place is inside the click listener : 
        Fragment_A Frag_A = new Fragment_A();
          
        FragmentManager fm1 = getSupportFragmentManager();
        FragmentTransaction transaction = fm1.beginTransaction();
             
        transaction.add(R.id.fragment_container, Frag_A);
        transaction.commit();


-> new Fragment -> get FragmentManager -> beginTransaction -> add new layout and commit.


One last thing is the Activity's layout. The activity's layout includes an empty FrameLayoutthat acts as the fragment container. 



<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"
    tools:context=".MainActivity" >

        <Button 
         android:id="@+id/button_id"
         android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/button_text" />

        
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
        
        
</RelativeLayout>





Monday, May 6, 2013

ActionBarSherlock configuration

1.
I'm creating a custom Theme, let's call it TestABS with parent the HOLO Theme ( in our case Sherlock ).
So now in my styles.xml I add the line :
<style name="Theme.TestABS" parent="@style/Theme.Sherlock"></style> 

2.
Later I'll edit Manifest file like this :

<activity
      android:name=".MainActivity"
      android:label="@string/app_name"
      android:theme="@style/Theme.TestABS"
      android:logo="@drawable/ad_logo">

3.
When Activity starts, the system adds ActionBar and the overflow menu by calling onCreateOptionsMenu().
This method inflates an XML resource which defines the menu items. This files is in the folder /res/menu. In those items on the XML file I have to add the android:showAsAction keyword, so now the items will appear as Action Items in my ActionBar and not Options Menu.

So a simple item should be like :

    <item
        android:id="@+id/menu_settings"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="Text Here" />



This works as long as I have an ActionBar in my Activity( When do I have an ActionBar ? When I add   android:theme="@style/Theme.HOLO" in my manifest file for android 3.0 and greater. For lower versions I need Theme.Sherlock . In both cases I can declare mine custom theme like I did above with TestABS ).


Links :
1) Adding ActionBarSherlock to your Project
2) Adding Items to the ActionBar 
3) The Overflow menu ( As a rule of thumb you should always use ifRoom, if you want the icon to be part of your action bar and you should use never if you want the item to always be part of the overflow menu. )








Wednesday, April 10, 2013

Add Marker to Google Map

To detect a long map click by the user, so add a new Marker, we need to implement OnMapLongClickListener Interface.

Then we set our map to listen for any calls when its long pressed :    mMap.setOnMapLongClickListener(this);

And now in our code we can add a new Marker every time the user long clicks the map :

mMap.addMarker(new MarkerOptions().position(point));

Monday, April 8, 2013

Detect user click on Map

To detect click on GoogleMap we implement OnMapClickListener Interface.
We add to our GoogleMap setOnMapClickListener . This sets a callback to the Interface when the map is clicked

Then we need to override the onMapClick(LatLng point) 


@Override 
public void onMapClick(LatLng point) { mMap.animateCamera(CameraUpdateFactory.newLatLng(point)); }


We are using CameraUpdateFactory to get a new CameraUpdate Object ( an object to modify a map's camera ) and animate to the new point with animateCamera.

Sunday, April 7, 2013

Display my Location - Google maps API V2


All we need to do is to use the method setMyLocationEnabled(boolean enabled) which enables the my-Location layer.
Like that :

private GoogleMap mMap;
mMap.setMyLocationEnabled(true);

Sunday, February 17, 2013

Fragments Tutorial - Simple 2 - Passing Data

Passing Data between Fragment and host Activity


To pass data from a Fragment to the host Activity we need to Define/declare an Interface and
Implement it on the Activity.

1. Declare an Interface on Fragment_A. 

public interface OnSomethingSelectedListener {
    public void passData(int position);
      }  

2. onAttach() : To be sure that Activity implements the Interface  onAttach callback method of Fragment_A  we instantiate an Instance of Ιnterface by casting the Activity  passed into onAttach().
The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.


@Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // This makes sure that the container activity has implemented the callback interface. If not, it throws an exception
        try {
            listener = (OnSomethingSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }



3. On Main Activity we implement the Interface like this :

public class MainActivity extends FragmentActivity implements OnSomethingSelectedListener


@Override
public void passData(int position) {
 Log.d(TAG, "Give me the result  " + position  );
 position = position +1;
 Log.d(TAG, "Give me the result  " + position  ); 
}


We just take the integer value parameter from the Fragment and add one to it.



4. A button on Fragment's layout so we can add onClick event
 

<button 
android:id="@+id/button_id" 
android:layout_height="wrap_content" 
android:layout_width="wrap_content" 
android:text="send Integer">
</button>

5. And on Fragment's onCreateView() we add the listener for the event:
Button button = (Button) view.findViewById(R.id.button_id);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Log.v(TAG, "onClick 1");
            listener.passData(5); //pass an Integer
        }
    });
We pass the value five to the method passData() Now when we click on the Button we open LogCat View and we see that value one has been added to the  value  of the parameter: