Saturday, April 26, 2014

AngularJs Pass Data Between Controllers

Hello,

This is my first blog on AngularJs. I have been working with AngularJs since last three or four weeks and I am very excited about this Framework. It has nice features like two way data binding, templates, MVVM model, directives. That makes this framework super cool. I will be adding more blogs in future for AngularJs. In this blog I will explain how to pass data between controllers.

For this first we have to understand $rootScope. Every AngularJs application has one root scope and all other scopes are children of root scope. It's like application wide global variable.

Now lets see how we can use this to share data between controllers. First we need a service which is common in both controllers. We will invoke a service function from a controller which wants to send data. Service will broadcast it and using $rootScope. While the receiver controller will listen to the broadcast event and receives that data. First lets crete a service and function.

var servicesModule = angular.module('myapp.broadcastservice', []);

servicesModule.factory('BroadcastService', ['$http', '$rootScope', function ($http, $rootScope) {

   var service = {};
   service.sendData = function(data){

      $rootScope.$broadcast('message', data);
   }

}

Now lets create sender controller.

appRoot.controller('SenderController', ['$scope', 'BroadcastService',
   function ($scope, BroadcastService) {
        $scope.sendData = function(){
              BroadcastService.sendData("My Message");
        }
   }
]);

Now lets create a receiver controller

appRoot.controller('ReceiverController', ['$scope', 'BroadcastService',
    function ($scope, BroadcastService) {
        $scope.$on('message', function(response, data) {
            console.log(data);
       });
    }
]);

As you can see from sender controller we invoke service function and broadcast message with event message and in receiver controller we receive it by listening to message event using $scope.$on.

This way you can pass data between AngularJs controllers. Hope this post helps you.   

Android Slide Menu like Facebook With Effect Like Navigation Drawer

Recently in one our project we have to build slide out menu like Facebook but with some difference. In Facebook app when slide menu opens the main content screen also goes left or right. While in our case main content should stat and menu should come over the content like Navigation Drawer. For certain reasons we could not use Navigation Drawer class as we have the fragments in the application.

So we accomplished it with some different manner. In this blog I will explain you how to do this. First lets see our Main Layout XML file.

&ltcom.myapp.layout.MainLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#221010" >

<!-- This holds our content -->
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

         <FrameLayout
                android:id="@+id/activity_main_content_fragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white" >
         </FrameLayout>
         <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="70dip"
                android:alpha="0.9"
                android:background="#d84047"
                android:orientation="horizontal" >

                <Button
                    android:id="@+id/activity_main_content_button_menu"
                    android:layout_width="30dip"
                    android:layout_height="30dip"
                    android:layout_marginBottom="10dip"
                    android:layout_marginTop="18dip"
                    android:background="@drawable/menu"
                    android:onClick="toggleMenu" />
         </RelativeLayout>
    </FrameLayout>

 <!-- This holds our menu -->

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal" >
    </LinearLayout>

</com. myapp.layout.MainLayout>

So in our layout we have FrameLayout with top toolbar with menu button which will open our menu. and a content layout which holds out main content. Now our menu should occupy 70% of available space when it opens so for that we have to set width and height for it. Lets create MainLayout class in app and configure this.

package com. myapp.layout;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.Scroller;


public class MainLayout extends LinearLayout {

int mainLayoutWidth;
private View menu;
private View content;
private int contentXOffset;
private MenuState currentMenuState = MenuState.HIDDEN;
private enum MenuState {
        HIDING,
        HIDDEN,
        SHOWING,
        SHOWN,
};
public MainLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
}

public MainLayout(Context context) {
        super(context);
}

// Overriding LinearLayout core methods
   
   
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);      
        mainLayoutWidth = MeasureSpec.getSize(widthMeasureSpec);
    }
   
    // This is called when MainLayout is attached to window
    // At this point it has a Surface and will start drawing.
    // Note that this function is guaranteed to be called before onDraw
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
       
        // Get our 2 child View
        menu = this.getChildAt(1);
        content = this.getChildAt(0);  
       
        // Initially hide the menu
        menu.setVisibility(View.GONE);

    }
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
     
        if(changed) {
            LayoutParams contentLayoutParams = (LayoutParams)content.getLayoutParams();
            contentLayoutParams.height = this.getHeight();
            contentLayoutParams.width = this.getWidth();

            // menu View occupies the full height, but certain width
            LayoutParams menuLayoutParams = (LayoutParams)menu.getLayoutParams();
            menuLayoutParams.height = this.getHeight();
            menuLayoutParams.width = mainLayoutWidth;
        }
        // Layout the child views  
       
        menu.layout(left, top, mainLayoutWidth*0.7 , bottom);
        content.layout(left, top, right , bottom);
       
    }

    public void toggleMenu() {
    this.calledFromToggleMenu = true;
        // Do nothing if sliding is in progress
        if(currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
            return;
       
        switch(currentMenuState) {
        case HIDDEN:
        //show menu here
        Log.v("log","current state is hidden");
       
        TranslateAnimation moveLefttoRight = new TranslateAnimation(menu.getWidth()*-1, 0, 0, 0);
       
        moveLefttoRight.setAnimationListener(new Animation.AnimationListener(){
           @Override
           public void onAnimationStart(Animation arg0) {
            menu.setVisibility(View.VISIBLE);
            menu.bringToFront();
           }          
           @Override
           public void onAnimationRepeat(Animation arg0) {
           }          
           @Override
           public void onAnimationEnd(Animation arg0) {
           
           }
        });
       
            moveLefttoRight.setDuration(300);
            moveLefttoRight.setFillAfter(true);
            menu.startAnimation(moveLefttoRight);
            currentMenuState = MenuState.SHOWN;
            break;
        case SHOWN:
        //hide menu here
        Log.v("log","current state is visible");
        TranslateAnimation moveRightoLeft = new TranslateAnimation(0, menu.getWidth()*-1, 0, 0);
        moveRightoLeft.setDuration(300);
        moveRightoLeft.setFillAfter(true);
            menu.startAnimation(moveRightoLeft);
            currentMenuState = MenuState.HIDDEN;
            moveRightoLeft.setAnimationListener(new Animation.AnimationListener(){
           @Override
           public void onAnimationStart(Animation arg0) {
           
           }          
           @Override
           public void onAnimationRepeat(Animation arg0) {
           }          
           @Override
           public void onAnimationEnd(Animation arg0) {
            Log.v("log","hiding menu");
            content.bringToFront();
           }
        });
            break;
        default:
            break;
        }
        // Begin querying
        //menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);
       
        // Invalite this whole MainLayout, causing onLayout() to be called
        //this.invalidate();
    }

}

As you can see in above class we have extended LinearLayout and it's core method and created an extended class. Where onLayout method we are hiding the menu and setting it's width to 70% width of the screen. Key function here is toggleMenu. It identifies the state of the menu and based on that show animation and show/hide the menu. You just have to call toggleMenu function when users taps on button. To close the menu user has to swipe left on the screen and it will close the menu. See the below code.

package com.myapp;
import com.myapp.layout.MainLayout;

public class MainActivity extends FragmentActivity implements
OnTouchListener{
public static MainLayout mainLayout;
      protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_market_place);
mainLayout = (MainLayout) this.getLayoutInflater().inflate(
R.layout.activity_main, null);
setContentView(mainLayout);
                btMenu = (Button) findViewById(R.id.activity_main_content_button_menu);
btMenu.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Show/hide the menu
mainLayout .toggleMenu(v);
}
});
      }

      @Override
       public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
super.dispatchTouchEvent(ev);

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN: {
// store the X value when the user's finger was pressed down
downXValue = ev.getX();
downYValue = ev.getY();
Log.v("", "= " + downYValue);
break;
}

case MotionEvent.ACTION_UP: {
// Get the X value when the user released his/her finger
float currentX = ev.getX();
float currentY = ev.getY();
// check if horizontal or vertical movement was bigger

if (Math.abs(downXValue - currentX) > Math.abs(downYValue
- currentY)) {
Log.v("", "x");
// going backwards: pushing stuff to the right

Log.v("log", " downXvalue - currentX "
+ (downXValue - currentX));

if (downXValue < currentX) {
Log.v("", "right");
if (-150 > (downXValue - currentX)) {
Log.v("log", "right if");
mainLayout.toggleMenu("OPEN");
} else {
Log.v("log", "right else");
}
}

// going forwards: pushing stuff to the left
if (downXValue > currentX) {
mainLayout. toggleMenu("CLOSE");

}

} else {
Log.v("", "y ");

if (downYValue < currentY) {
Log.v("", "down");

}
if (downYValue > currentY) {
Log.v("", "up");

}
}
break;
}

}
return true;
}
}

As you can see in above code we are setting MainLayout as content layout for the activity added on click listener for menu button. Which invokes toggleMenu function of mainLayout and toggles the menu. Also we have added dispatchTouchEvent method where we tracking user motion and invoke toggle menu method.

Hope this helps.

Android Use FrameLayout for Overlapping Items

Hello,

Recently in one of my project we have a layout where we have transparent top and bottom bar and which overlaps content of the screen. Content was the list view so when you scroll up or down the list view content goes under overlapping top and bottom bar where we can see it as the both top and bottom bars were transparent. Something like this.


So in this blog I am going to explain how to do this type of layout. I have used FrameLayout for this. As FrameLayout automatically sets the z-index for all it's child items as per the order. So following is our layout XML for this.

 <!-- Main frame layout -->
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

<!-- Main Content layout -->
<LinearLayout
            android:layout_width="fill_parent"
            android:id="@+id/contentPane"
            android:layout_height="wrap_content"
            android:layout_weight="1" >
</LinearLayout>

<!-- Relative Layout for top and bottom bar -->
<RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >

<!-- top bar -->
<RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="70dip"
                android:alpha="0.9"
                android:orientation="horizontal" >
 </RelativeLayout>

<!-- Bottom bar -->
<RelativeLayout
                android:layout_width="fill_parent"
                android:layout_alignParentBottom="true"
                android:layout_height="70dip"
                android:alpha="0.9"
                android:orientation="horizontal" >
 </RelativeLayout>

</RelativeLayout>

</FrameLayout>

As you can see in above XML first we have frame layout inside frame layout we have linear layout as our content layout where we have set layout weight property as 1 so this component will take whole space for the frame layout.  After that we have used Relative layout and inside it we have or top and bottom bar as relative layout for bottom bar we are using android:layout_alignParentBottom config and set is true so it will go to bottom.  This is how you can have overlapping views in android.  Hopw this helps you.