tag:blogger.com,1999:blog-45357376566249271312024-03-14T07:11:59.753-07:00Shardul PrabhuDevelopment experiences with Google Android, Apple iOS and PHP framework
Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-4535737656624927131.post-70142204771790618342013-06-09T12:52:00.000-07:002013-06-09T12:59:09.368-07:00Overflowing ListView<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinSWDgqAXMv0P-G257o1d7rvymz5PyLvFqYBrQbpep_EI4sRS3XtSncc1qJ8cdvvx9Wyox3cwCQa4czDxGOVUOEzLlCwSTd4T_mjK6V8F12OeSAK0TjrrceyJL9sUo9bDR654x9q5pxUE/s1600/overflowingscroll-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinSWDgqAXMv0P-G257o1d7rvymz5PyLvFqYBrQbpep_EI4sRS3XtSncc1qJ8cdvvx9Wyox3cwCQa4czDxGOVUOEzLlCwSTd4T_mjK6V8F12OeSAK0TjrrceyJL9sUo9bDR654x9q5pxUE/s1600/overflowingscroll-1.png" height="320" width="180" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNwNJ3LdEbOwX1bnTYzduY2aXYtA9F17qd-iWr_pmkj50pCDzy8Rv17GbUSUTUXAjKB8cu0tPzVgirK8U_XvPQOw3fPfL5NFqGwBrOrkmQfeAGB32Ydy1cbMHU33UW2oLTW2dr_mWmQYE/s1600/overflowingscroll-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNwNJ3LdEbOwX1bnTYzduY2aXYtA9F17qd-iWr_pmkj50pCDzy8Rv17GbUSUTUXAjKB8cu0tPzVgirK8U_XvPQOw3fPfL5NFqGwBrOrkmQfeAGB32Ydy1cbMHU33UW2oLTW2dr_mWmQYE/s1600/overflowingscroll-2.png" height="320" width="180" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxykgxQ3XUL5tVuNpvMPCJX-HUdUwsPaiJZ9AOKAiyOfm1mYoaAGR2f2gGIA4U_edtmblIJG4gN-0b7JX3ur5sfWkYTU5QSTD2adadfDPQzetLH9Vzv7HNlLbhuusDzER1D3oBtFzxLQ/s1600/overflowingscroll-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxykgxQ3XUL5tVuNpvMPCJX-HUdUwsPaiJZ9AOKAiyOfm1mYoaAGR2f2gGIA4U_edtmblIJG4gN-0b7JX3ur5sfWkYTU5QSTD2adadfDPQzetLH9Vzv7HNlLbhuusDzER1D3oBtFzxLQ/s1600/overflowingscroll-3.png" height="320" width="180" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-U-wxW0Hkv0cOJeL0pMtkXqZs40T2thICskWQesHMvKYGZKNIlGekddYn0sn9ZfAmQJxxbgEEFNEj4rfaHp6kJ9FF8Xa1EVYGkSNrZgO9VPaPfWEnpeUVpYo9AoNwxbcwZMt-J4PIdE/s1600/overflowingscroll-5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-U-wxW0Hkv0cOJeL0pMtkXqZs40T2thICskWQesHMvKYGZKNIlGekddYn0sn9ZfAmQJxxbgEEFNEj4rfaHp6kJ9FF8Xa1EVYGkSNrZgO9VPaPfWEnpeUVpYo9AoNwxbcwZMt-J4PIdE/s1600/overflowingscroll-5.png" height="320" width="180" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-size: large;"><b>What this project is : </b></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<ul>
<li style="text-align: left;">Overflowing list lays out items across a view when list is scrolled to bottom</li>
<li style="text-align: left;">Allows interaction on list items as well as view covered</li>
<li style="text-align: left;">A behaviour like <i>clippingChildren</i> to false with some initial top padding</li>
</ul>
<div style="text-align: left;">
<b style="font-size: x-large;">What this project is NOT:</b><b style="font-size: x-large;"> </b></div>
<br />
<ul style="text-align: center;">
<li style="text-align: left;">Best way to do this, its a hacky solution, an ideal solution would be overriding AdapterView or a ViewGroup</li>
</ul>
<div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<b style="font-size: x-large;">Why did I implement this:</b><b style="font-size: x-large;"> </b></div>
<br />
<ul style="text-align: center;">
<li style="text-align: left;">Imitating an implementation from an iOS app.</li>
</ul>
<div>
<div>
<b style="font-size: x-large;">Source:</b><b style="font-size: x-large;"> </b></div>
</div>
</div>
<div>
<a href="https://github.com/shardul/Android/tree/master/OverflowiingScrollView">https://github.com/shardul/Android/tree/master/OverflowiingScrollView</a></div>
</div>
Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.com0tag:blogger.com,1999:blog-4535737656624927131.post-61259189522543876052012-11-19T08:53:00.000-08:002012-11-19T08:53:00.658-08:00Infinite Scrolling with reusable views iOS<div dir="ltr" style="text-align: left;" trbidi="on">
UIScrollView in iOS provides a large ground to play with in iOS, UITableView being one of those.<br />
But as the ground is large and opportunity as well, memory of a device should not be incorrectly used.<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMHmsB7XMOoD2wNBIdQb9XzyclA6i1Eo01SGMVufdAyoWmpSPeU_JD_YQa-hBxmEOu1ig2_zPZTvfaPcDT3mbzpyl_Qzm-qXC7oEwV4EFRiwTvl8zd9cEac1wdIOhjAOv_TczSAtLG31I/s1600/iOS+Simulator+Screen+shot+19-Nov-2012+3.09.09+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMHmsB7XMOoD2wNBIdQb9XzyclA6i1Eo01SGMVufdAyoWmpSPeU_JD_YQa-hBxmEOu1ig2_zPZTvfaPcDT3mbzpyl_Qzm-qXC7oEwV4EFRiwTvl8zd9cEac1wdIOhjAOv_TczSAtLG31I/s400/iOS+Simulator+Screen+shot+19-Nov-2012+3.09.09+PM.png" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The example, that we have today shows "recycled" or "reusable" views to create an infinite scrolling behaviour. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Some highlights of the implementation</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>There are 3 views at most at a single time</li>
<li>UIScrollView.contentSize is set to compose all of the 3</li>
<li>Whenever scrolling is performed, UIScrollView.contentOffset is set back to center.</li>
<li>After contentOffset is at center, depending upon the scrolling (left or right) the new center position is calculated and view at center is replaced by the view expected for the position. This happens smoothly enough and user doesn't suspect the happening behind scene.</li>
<li>After center view is created the view before and after is created as well.</li>
<li>If the current position is the first (index 0) the view before is the last view(viewCount-1) and if current position is last (index, viewCount-1) next view is first (index 0). Giving a circular scrolling behaviour</li>
</ul>
<div>
The example demonstrates the same, with infinite scroll through various iPhone versions. Complete example can be <b>downloaded from : <a href="https://bitbucket.org/shardul/ios/src">https://bitbucket.org/shardul/ios/src</a></b><br />
<br />
We achieve this by subclassing UIScrollView, lets look at the implementation.</div>
<h3 style="text-align: left;">
InfiniteScrollView.h</h3>
<pre><code>
//
// InfinitePagingScrollView.h
// InfinitePagingScrollView
//
// Created by Shardul Prabhu on 18/11/12.
// Copyright (c) 2012 Shardul Prabhu. All rights reserved.
//
#import <uikit it.h="it.h">
@protocol InfinitePagingScrollViewDelegate;
@interface InfinitePagingScrollView : UIScrollView
@property (nonatomic,assign) id<infinitepagingscrollviewdelegate> delegateForViews;
@end
@protocol InfinitePagingScrollViewDelegate
- (UIView*)setupView:(UIView*)reusedView forPosition:(NSUInteger) position;
- (NSUInteger) noOfViews;
- (void)clearView:(UIView*)reusableView;
@end</infinitepagingscrollviewdelegate></uikit></code>
</pre>
<br />
<br />
We will use delegation model of implementing.<br />
InfinitePagingScrollView.h declares InfinitePagingScrollViewDelegate which requires implementation of<br />
<br />
<br />
- (UIView*)setupView:(UIView*)reusedView forPosition:(NSUInteger) position;<br />
<br />
This method should return a UIView to be shown defined position. If reusedView is nil a new view should be created, otherwise, the same view can be reused by just updating the display logic.<br />
<br />
- (NSUInteger) noOfViews;<br />
<br />
The total no of views the delegate wants to scroll through<br />
<br />
- (void)clearView:(UIView*)reusableView;<br />
<br />
Before sending the reusedView to setupView method call, clearView for the same is called. So appropriate clearance can be made.<br />
<br />
<h3 style="text-align: left;">
InfiniteScrollView.m</h3>
<div>
<pre><code>
//
// InfinitePagingScrollView.m
// InfinitePagingScrollView
//
// Created by Shardul Prabhu on 18/11/12.
// Copyright (c) 2012 Shardul Prabhu. All rights reserved.
//
#import "InfinitePagingScrollView.h"
@protocol InfinitePagingScrollViewDelegate;
static const NSUInteger numOfReusableViews = 3;
@interface InfinitePagingScrollView(){
NSMutableArray *visibleViews;
UIView *containerView;
NSUInteger currentPosition;
}
@end
@implementation InfinitePagingScrollView
@synthesize delegateForViews=_delegateForViews;
- (id)initWithCoder:(NSCoder *)aDecoder{
if((self= [super initWithCoder:aDecoder])){
visibleViews=[[NSMutableArray alloc] init];
containerView = [[UIView alloc] init];
[self addSubview:containerView];
[self setShowsHorizontalScrollIndicator:NO];
}
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
if(self.delegateForViews){
CGPoint contentOffset = self.contentOffset;
if([self.delegateForViews noOfViews]>numOfReusableViews){
NSUInteger centerIndex=visibleViews.count/2;
NSUInteger noOfViews=[self.delegateForViews noOfViews];
UIView *centerView=[visibleViews objectAtIndex:centerIndex];
CGPoint centerViewOrigin=centerView.frame.origin;
CGSize centerViewSize=centerView.frame.size;
CGFloat offsetDifference=contentOffset.x-centerViewOrigin.x;
CGFloat offsetDifferenceAbs=fabs(contentOffset.x-centerViewOrigin.x);
if(offsetDifferenceAbs>=centerViewSize.width){
if(offsetDifference<0){
currentPosition--;
}else{
currentPosition++;
}
self.contentOffset=centerViewOrigin;
currentPosition=[self getPosition:currentPosition noOfViews:noOfViews];
[self.delegateForViews clearView:centerView];
[self.delegateForViews setupView:centerView forPosition:currentPosition];
for (int i=centerIndex-1; i>=0; i--) {
UIView* prevView=[visibleViews objectAtIndex:i];
[self.delegateForViews clearView:prevView];
[self.delegateForViews setupView:prevView forPosition:
[self getPosition:currentPosition-1 noOfViews:noOfViews]];
}
for (int i=centerIndex+1; i<visibleViews.count; i++) {
UIView* nextView=[visibleViews objectAtIndex:i];
[self.delegateForViews clearView:nextView];
[self.delegateForViews setupView:nextView forPosition:
[self getPosition:currentPosition+1 noOfViews:noOfViews]];
}
}
}
}
}
- (NSUInteger)getPosition:(NSUInteger) aPosition noOfViews:(NSUInteger) count{
if(aPosition==-1){
aPosition=count-1;
}
else if(aPosition==(count)){
aPosition=0;
}
return aPosition;
}
- (void)setDelegateForViews:(id<InfinitePagingScrollViewDelegate>)aDelegateForViews{
_delegateForViews=aDelegateForViews;
[self invalidateViews];
}
- (void) invalidateViews{
if(self.delegateForViews){
currentPosition=1;
NSUInteger noOfViews=MIN(numOfReusableViews, [self.delegateForViews noOfViews]);
containerView.frame= CGRectMake(0, 0, self.frame.size.width*noOfViews,
self.frame.size.height);
self.contentSize=CGSizeMake(self.frame.size.width*noOfViews, self.frame.size.height);
for (int i=0; i<noOfViews; i++) {
UIView* view=[self.delegateForViews setupView:nil forPosition:i];
CGRect frame=view.frame;
view.frame=CGRectMake(frame.origin.x+(frame.size.width*i),
frame.origin.y,
frame.size.width,
frame.size.height);
[containerView addSubview:view];
[visibleViews addObject:view];
}
}
}
@end</code></pre>
</div>
<br />
<br />
layoutSubViews is where all the magic happens. Offsets are adjusted depending upon the scroll and delegate calls are made accordingly.<br />
<br />
<h3 style="text-align: left;">
ViewController.m</h3>
<div>
<pre><code>
//
// ViewController.m
// InfinitePagingScrollView
//
// Created by Shardul Prabhu on 18/11/12.
// Copyright (c) 2012 Shardul Prabhu. All rights reserved.
//
#import "ViewController.h"
#import "InfinitePagingScrollView.h"
@interface ViewController () <InfinitePagingScrollViewDelegate>{
NSArray *iPhoneVersions;
}
@property (weak, nonatomic) IBOutlet InfinitePagingScrollView *infiniteScrollView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
iPhoneVersions=[[NSArray alloc] initWithObjects:@"iPhone",@"iPhone 3G",@"iPhone 3GS",
@"iPhone 4",@"iPhone 4S",@"iPhone 5", nil];
}
- (void)viewDidAppear:(BOOL)animated{
self.infiniteScrollView.delegateForViews=self;
}
- (NSUInteger)noOfViews{
return iPhoneVersions.count;
}
- (UIView*)setupView:(UIView *)reusableView forPosition:(NSUInteger)position{
UIView* view=reusableView;
if(view==nil){
UIStoryboard *storyboard = [UIStoryboard
storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
UIViewController *viewController = [storyboard
instantiateViewControllerWithIdentifier:@"iPhoneViewController"];
view=viewController.view;
[(UILabel*)view setTextAlignment:NSTextAlignmentCenter];
view.frame=self.infiniteScrollView.frame;
}
[(UILabel*)view setText:[iPhoneVersions objectAtIndex:position]];
[view setBackgroundColor:[UIColor colorWithWhite:1.0-(position/2.0*0.1) alpha:1.0]];
[view setUserInteractionEnabled:YES];
UITapGestureRecognizer* tapGesture=[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(tapped:)];
[view addGestureRecognizer:tapGesture];
return view;
}
- (void)clearView:(UIView*)reusableView{
[reusableView setBackgroundColor:[UIColor clearColor]];
[(UILabel*)reusableView setFont:[UIFont systemFontOfSize:16.0]];
[reusableView removeGestureRecognizer:[reusableView.gestureRecognizers lastObject]];
}
- (void)tapped:(UIGestureRecognizer*) gestureRecognizer{
[((UILabel*)gestureRecognizer.view) setFont:[UIFont boldSystemFontOfSize:16.0]];
}
@end
</code></pre>
</div>
This shows the implementation of protocol. When new views are setup a UITapGestureRecognizer is set which makes the label bold and clearView sets back to normal.<br />
<br />
I hope this was helpful, and will help you as a developer. Don't forget to share this with your friends, and comment below. I am open to refinement as well, I am learning iOS as well. :-)</div>
Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.com0tag:blogger.com,1999:blog-4535737656624927131.post-32355444045365630852012-09-06T06:49:00.001-07:002012-09-07T03:04:05.032-07:00Google Now Cards Layout<div dir="ltr" style="text-align: left;" trbidi="on">
If you are a fan of Google's android applications, you must haven't missed cards animation that Google Now brings in on Android 4.1, Jelly Bean.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a alt="Google Now Cards Layout on Jellybean" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghdLT9ycCNSsspNiuhtzU5qhA3qg1nuIj06qDdoVxPoC-c9OZo6gUqmMK_FEcvtSZrXhvUk6Sg7ovYTBa-7oz_C7ieOT-QUnAwzapBNmu38XDXONr5ymqxJfR_wrmg0GFHqwu0WcuOHBk/s1600/device-2012-09-06-164412.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img title="Google Now Cards Layout on Jellybean" alt="Google Now Cards Layout on Jellybean" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghdLT9ycCNSsspNiuhtzU5qhA3qg1nuIj06qDdoVxPoC-c9OZo6gUqmMK_FEcvtSZrXhvUk6Sg7ovYTBa-7oz_C7ieOT-QUnAwzapBNmu38XDXONr5ymqxJfR_wrmg0GFHqwu0WcuOHBk/s400/device-2012-09-06-164412.png" width="225" /></a></div>
<br />
Lets see how to create these smooth animations.<br />
<br />
You can browse the source here : <a alt="Google Now Cards Layout Github repository link" href="https://github.com/shardul/Android/tree/master/NowLayout">https://github.com/shardul/Android/tree/master/NowLayout</a><br />
<br />
<h3 style="text-align: left;">
Step 1 : Animations and Styles</h3>
<div>
There are two animations of similar sliding transition, differing slightly for alternating cards (technically <i>Views</i>). One rotating in from left and other for right. </div>
<div>
<br /></div>
<h4 style="text-align: left;">
slide_up_left.xml</h4>
<div>
<pre><code>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator" >
<translate
android:duration="@integer/config_slide_time"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="@integer/config_slide_time"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<rotate
android:duration="@integer/config_slide_time"
android:fromDegrees="25"
android:pivotX="0"
android:pivotY="0"
android:toDegrees="0" />
</set>
</code></pre>
</div>
<br />
<h4 style="text-align: left;">
slide_up_right.xml</h4>
<div>
<pre><code>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator" >
<translate
android:duration="@integer/config_slide_time"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="@integer/config_slide_time"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<rotate
android:duration="@integer/config_slide_time"
android:fromDegrees="-25"
android:pivotX="100%"
android:pivotY="0"
android:toDegrees="0" />
</set>
</code></pre>
</div>
<br />
These animations will create alternate card animations.<br />
<br />
<h4 style="text-align: left;">
NowLayout.java</h4>
<div>
<pre><code>
package com.shardul.nowlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
public class NowLayout extends LinearLayout implements OnGlobalLayoutListener {
public NowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initLayoutObserver();
}
public NowLayout(Context context) {
super(context);
initLayoutObserver();
}
private void initLayoutObserver() {
// force vertical orientation and add observer
setOrientation(LinearLayout.VERTICAL);
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
final int heightPx =getContext().getResources().
getDisplayMetrics().heightPixels;
boolean inversed = false;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
int[] location = new int[2];
child.getLocationOnScreen(location);
if (location[1] > heightPx) {
break;
}
if (!inversed) {
child.startAnimation(
AnimationUtils.loadAnimation(getContext(),
R.anim.slide_up_left));
} else {
child.startAnimation(
AnimationUtils.loadAnimation(getContext(),
R.anim.slide_up_right));
}
inversed = !inversed;
}
}
}
</code></pre>
</div>
<br />
This is where all the magic will happen. To create alternating animations we can definitely grab each child and start respective animation in activity but a better approach would be to create custom layout and handle animation there which is a better approach to take.<br />
<br />
<h4 style="text-align: left;">
Integrating </h4>
<div>
<br />
Now we have to make use of <i>NowLayout</i> in our activity.</div>
<h4 style="text-align: left;">
main.xml</h4>
<div>
<pre><code>
<ScrollView 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:fillViewport="true" >
<com.shardul.nowlayout.NowLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e3e3e3"
android:orientation="vertical" >
<TextView
android:id="@+id/txtView"
style="@style/nowCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<TextView
android:id="@+id/txtView"
style="@style/nowCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<TextView
android:id="@+id/txtView"
style="@style/nowCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<TextView
android:id="@+id/txtView"
style="@style/nowCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<TextView
android:id="@+id/txtView"
style="@style/nowCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
</com.shardul.nowlayout.NowLayout>
</ScrollView>
</code></pre>
</div>
<br />
<h4 style="text-align: left;">
MainActivity.java</h4>
<div>
<pre><code>
package com.shardul.nowlayout;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
</code></pre>
</div>
And there you have it. Run the app and see sliding cards similar to Google Now app.<br />
<br />
Make sure you share with your friends if you like what you created.<br />
<br />
You can also learn about <a alt="Creating Chrome Style Help Popups on Android" href="http://shardulprabhu.blogspot.in/2012/08/blog-post_29.html">Creating Chrome Style Help Popups on Android</a>.</div>Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.com16tag:blogger.com,1999:blog-4535737656624927131.post-91716085355041930092012-09-05T09:17:00.001-07:002012-09-07T03:09:57.943-07:00SOAP Calls With SOAPIntentService<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Wiki</b>: <i><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;">SOAP</span><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;">, originally defined as </span><b style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;">Simple Object Access Protocol</b><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;">, is a </span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Protocol_(computing)" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Protocol (computing)">protocol</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> specification for exchanging structured information in the implementation of </span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Web_Service" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Web Service">Web Services</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> in </span><a href="http://en.wikipedia.org/wiki/Computer_network" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Computer network">computer networks</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;">. It relies on </span><a href="http://en.wikipedia.org/wiki/XML" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="XML">Extensible Markup Language</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> (XML) for its message format, and usually relies on other</span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Application_Layer" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Application Layer">Application Layer</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> protocols, most notably </span><a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Hypertext Transfer Protocol">Hypertext Transfer Protocol</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> (HTTP) and </span><a href="http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol" style="background-color: white; background-image: none; color: #0b0080; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px; text-decoration: none;" title="Simple Mail Transfer Protocol">Simple Mail Transfer Protocol</a><span style="background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.200000762939453px;"> (SMTP), for message negotiation and transmission.</span></i><br />
<br />
Being a developer, various server interaction methodologies come across you. SOAP being one of them when high security and reliability of transmission is concerned during server communication. Though it adds overhead (large payloads) it largely being used for enterprise level apps.<br />
<br />
By default, SOAP isn't bundled with Android (unlike JSON). We have external libraries available which can be used to achieve this task.<br />
<br />
One of these is kSoap2, official project <a href="http://code.google.com/p/ksoap2-android/">http://code.google.com/p/ksoap2-android/</a><br />
<br />
<h3 style="text-align: left;">
Lets talk about SOAPIntentService</h3>
<div>
<b><br /></b></div>
<div>
<b>Android Docs : </b><i>IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.</i></div>
<div>
<i><br /></i></div>
<div>
<i>This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.</i></div>
<div>
<i><br /></i></div>
<div>
<i>All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.</i></div>
<div>
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a alt="SOAPIntentService working" title="SOAPIntentService working" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyy4yLSaqzy3BgOlB9w8UuwoaucdvLT0bIb6UPpdZGA7J2Dk0ZHoyfhD5amV1b1C3uKSztHNiA4ARYo78Wzs-EDZV59mnbicByGh0jJbNKzGPJt1lGeFfBY_XM2p5N31C5CCCs_oN0ASY/s1600/soap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="SOAPIntentService working" title="SOAPIntentService working" border="0" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyy4yLSaqzy3BgOlB9w8UuwoaucdvLT0bIb6UPpdZGA7J2Dk0ZHoyfhD5amV1b1C3uKSztHNiA4ARYo78Wzs-EDZV59mnbicByGh0jJbNKzGPJt1lGeFfBY_XM2p5N31C5CCCs_oN0ASY/s400/soap.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
SOAP Intent Service, accepts a call and executes it on another thread, and responds back to caller via </div>
<div>
<a href="http://developer.android.com/reference/android/content/BroadcastReceiver.html">Broadcast Receiver</a><br />
<br />
It's also designed to cache on failure when POST is set as request type.<br />
<br />
You can acquire source from here : <a alt="SOAPIntentService Github repository" title="SOAPIntentService Github repository" href="https://github.com/shardul/Android/tree/master/SoapIntentService">https://github.com/shardul/Android/tree/master/SoapIntentService</a><br />
<br />
<h2 style="text-align: left;">
Usage</h2>
</div>
<div>
<pre><code>
// initialise request helper with appropriate parameters from wsdl definition
SOAPRequestHelper soapRequestHelper = new SOAPRequestHelper(namespace,
action, methodName, url);
// set properties for request using SOAPNameValuePair instances
SOAPNameValuePair[] props = new SOAPNameValuePair[2];
props[0]=new SOAPNameValuePair("param1","value1");
props[1]=new SOAPNameValuePair("param2","value2");
soapRequestHelper.setProperties(props);
// optionally set headers for request using SOAPNameValuePair instances
SOAPNameValuePair[] headers = new SOAPNameValuePair[2];
headers[0]=new SOAPNameValuePair("header1","headervalue1");
headers[1]=new SOAPNameValuePair("header2","headervalue2");
soapRequestHelper.setHeaders(headers);
//perform a call to SOAPIntentService using
soapRequestHelper.performSOAPRequest(this, responseReceiver);
</code></pre>
</div>
<br />
<div class="p1">
responseReceiver defined above is a BroadcastReceiver and is an optional parameter. It should only be used when caller do bothers about the response. responseReceiver will be internally registered thus it should accompany a context.unregisterReceiver(responseReceiver) when service call is dealt with.</div>
<div class="p1">
<br /></div>
<div class="p1">
Heres how responseReceiver code definition should look like</div>
<div class="p1">
<br /></div>
<div class="p1">
<pre><code>
private class ResponseReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// initialise response received
SOAPResponseHelper soapResponseHelper = new SOAPResponseHelper(
intent);
//check if theres an exception
if (!soapResponseHelper.isException()) {
responseMap = soapResponseHelper.getResponseMap();
showDialog(DIALOG_RESPONSE);
} else {
Toast.makeText(SoapIntentActivityActivity.this,
soapResponseHelper.getException().toString(),Toast.LENGTH_LONG).show();
}
}
}
</code></pre>
</div>
<div class="p1">
<br /></div>
<div class="p1">
Additionally caching can be enabled on the call by setting requestType as post of SOAPRequetHelper class<br />
<br />
<pre><code>
soapRequestHelper.setRequestType(SOAPRequestHelper.REQUEST_TYPE_POST)
</code></pre>
</div>
<br />
And don't forget to include internet permission in your AndroidManifest.xml<br />
<br />
<pre><code>
<uses-permission android:name="android.permission.INTERNET" />
</code></pre>
<br />
<br />
For further implementation details, you can browse sample code here.<br />
<br />
<a alt="SOAPIntentService Github SOAPIntentActivityActivity.java" title="SOAPIntentService Github SOAPIntentActivityActivity.java" href="https://github.com/shardul/Android/blob/master/SoapIntentService/src/com/shardul/android/soapservice/activities/SoapIntentActivityActivity.java">https://github.com/shardul/Android/blob/master/SoapIntentService/src/com/shardul/android/soapservice/activities/SoapIntentActivityActivity.java</a><br />
<br />
Feel free to email me or post comments regarding implementation and enhancements.<br />
</div>Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.com0tag:blogger.com,1999:blog-4535737656624927131.post-2566978928423519432012-08-29T05:52:00.002-07:002012-09-07T03:06:53.477-07:00Chrome Style Help Popups<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
If you love browsing on your phone with Google Chrome browser, you must have seen these quick help popups that appear when you first start Chrome.</div>
<div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a title="Chrome Style Help Popups Demo" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RapFVDD5cYIm4YHg0J2fqA9hkHkRMMMLpMD5bh_uxdDETfnKZXBubWfZ9E6tba3j_Qug6rReOyp7UJLD_urtplceeGvcDGLOp1hjt91N3NxfF_7sVM4WGwWYvvIAlYMDwn9DwynFB7s/s1600/device-2012-08-29-160335.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img title="Chrome Style Help Popups Demo" alt="Chrome Style Help Popups Demo" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RapFVDD5cYIm4YHg0J2fqA9hkHkRMMMLpMD5bh_uxdDETfnKZXBubWfZ9E6tba3j_Qug6rReOyp7UJLD_urtplceeGvcDGLOp1hjt91N3NxfF_7sVM4WGwWYvvIAlYMDwn9DwynFB7s/s400/device-2012-08-29-160335.png" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Those "floating" popups will surely come handy when you want to show some quick info about your in-app widgets or to be more technical <i>Views</i> in your application. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can pull / download entire Eclipse project source from my Github repo :</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a title="Creating Chrome Style Help Popups Github" href="https://github.com/shardul/Android/tree/master/ChromeStyleHelpPopups">https://github.com/shardul/Android/tree/master/ChromeStyleHelpPopups</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Or stick through to see how to create one of these.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="text-align: left;">
Step 1 : Creating Resources Required</h3>
<div>
First lets create some resources that will create look and feel of those popups. Create a new Android project and add following resources to the project directory</div>
<div>
<br /></div>
<h4 style="text-align: left;">
Background: </h4>
<div>
<pre><code>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp">
<solid android:color="#3a68a9">
<stroke android:color="#32588c" android:width="1dp">
</stroke></solid></corners></shape>
</code></pre>
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
This will define a new shape drawable, save this in <b>res/drawable/blue_bg.xml</b><br />
<b><br /></b>
<br />
<h4 style="text-align: left;">
<b>Floating Animation</b></h4>
</div>
<div>
Create new animation which will be used to create a floating fill to our popups, in this case defined animation is much faster as that in default Chrome application but you can play with it according to your needs. Following snippet creates an animation which will repeat it self for infinite times.</div>
<div>
<br /></div>
<div>
<pre><code>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:interpolator="@android:anim/bounce_interpolator"
android:duration="1000"
android:fillAfter="true"
android:fromYDelta="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toYDelta="5%" />
</set>
</code></pre>
</div>
<br />
Save it as <b>res/anim/float_anim.xml</b>.<br />
<br />
<h3 style="text-align: left;">
Step 2 : Popup definition files</h3>
<div>
Now lets start with popup declarations. To match look and feel, lets define a layout, composing an up arrow (<i>ImageView</i>)<i> , </i>text (<i>TextView</i>) and down arrow (<i>ImageView</i>). </div>
<div>
<br /></div>
<h4 style="text-align: left;">
Popup layout</h4>
<div>
<pre><code>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/arrow_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/down_arrow" />
<TextView
android:id="@+id/text"
style="@style/ChromeStylePopup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/blue_bg"
android:scrollbars="vertical" />
<ImageView
android:id="@+id/arrow_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-1dip"
android:src="@drawable/up_arrow" />
</LinearLayout>
</code></pre>
</div>
<br />
Save this layout as <b>res/layout/popup.xml</b><br />
<b><br /></b>You will have to import 2 arrow images one pointing up and other pointing down to compile this.<br />
<br />
This layout is also referring to an external style definition, which we will create next<br />
<br />
<pre><code>
<resources>
<style name="ChromeStylePopup" parent="android:Widget.TextView">
<item name="android:gravity">center</item>
<item name="android:minHeight">50dp</item>
<item name="android:minWidth">75dp</item>
<item name="android:maxWidth">150dp</item>
<item name="android:padding">6dp</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textStyle">bold</item>
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
</style>
</resources>
</code></pre>
<br />
This wil go into <b>res/values/styles.xml</b>.<br />
<br />
<h3 style="text-align: left;">
Step 3 : ChromeHelpPopup.java</h3>
<div>
<pre><code>
package com.example.chromestylehelppopups;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.method.ScrollingMovementMethod;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
public class ChromeHelpPopup {
protected WindowManager mWindowManager;
protected Context mContext;
protected PopupWindow mWindow;
private TextView mHelpTextView;
private ImageView mUpImageView;
private ImageView mDownImageView;
protected View mView;
protected Drawable mBackgroundDrawable = null;
protected ShowListener showListener;
public ChromeHelpPopup(Context context, String text, int viewResource) {
mContext = context;
mWindow = new PopupWindow(context);
mWindowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setContentView(layoutInflater.inflate(viewResource, null));
mHelpTextView = (TextView) mView.findViewById(R.id.text);
mUpImageView = (ImageView) mView.findViewById(R.id.arrow_up);
mDownImageView = (ImageView) mView.findViewById(R.id.arrow_down);
mHelpTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
mHelpTextView.setSelected(true);
}
public ChromeHelpPopup(Context context) {
this(context, "", R.layout.popup);
}
public ChromeHelpPopup(Context context, String text) {
this(context);
setText(text);
}
public void show(View anchor) {
preShow();
int[] location = new int[2];
anchor.getLocationOnScreen(location);
Rect anchorRect = new Rect(location[0], location[1], location[0]
+ anchor.getWidth(), location[1] + anchor.getHeight());
mView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int rootHeight = mView.getMeasuredHeight();
int rootWidth = mView.getMeasuredWidth();
final int screenWidth = mWindowManager.getDefaultDisplay().getWidth();
final int screenHeight = mWindowManager.getDefaultDisplay().getHeight();
int yPos = anchorRect.top - rootHeight;
boolean onTop = true;
if (anchorRect.top < screenHeight / 2) {
yPos = anchorRect.bottom;
onTop = false;
}
int whichArrow, requestedX;
whichArrow = ((onTop) ? R.id.arrow_down : R.id.arrow_up);
requestedX = anchorRect.centerX();
View arrow = whichArrow == R.id.arrow_up ? mUpImageView
: mDownImageView;
View hideArrow = whichArrow == R.id.arrow_up ? mDownImageView
: mUpImageView;
final int arrowWidth = arrow.getMeasuredWidth();
arrow.setVisibility(View.VISIBLE);
ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) arrow
.getLayoutParams();
hideArrow.setVisibility(View.INVISIBLE);
int xPos = 0;
// ETXTREME RIGHT CLIKED
if (anchorRect.left + rootWidth > screenWidth) {
xPos = (screenWidth - rootWidth);
}
// ETXTREME LEFT CLIKED
else if (anchorRect.left - (rootWidth / 2) < 0) {
xPos = anchorRect.left;
}
// INBETWEEN
else {
xPos = (anchorRect.centerX() - (rootWidth / 2));
}
param.leftMargin = (requestedX - xPos) - (arrowWidth / 2);
if (onTop) {
mHelpTextView.setMaxHeight(anchorRect.top - anchorRect.height());
} else {
mHelpTextView.setMaxHeight(screenHeight - yPos);
}
mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos);
mView.setAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.float_anim));
}
protected void preShow() {
if (mView == null)
throw new IllegalStateException("view undefined");
if (showListener != null) {
showListener.onPreShow();
showListener.onShow();
}
if (mBackgroundDrawable == null)
mWindow.setBackgroundDrawable(new BitmapDrawable());
else
mWindow.setBackgroundDrawable(mBackgroundDrawable);
mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
mWindow.setTouchable(true);
mWindow.setFocusable(true);
mWindow.setOutsideTouchable(true);
mWindow.setContentView(mView);
}
public void setBackgroundDrawable(Drawable background) {
mBackgroundDrawable = background;
}
public void setContentView(View root) {
mView = root;
mWindow.setContentView(root);
}
public void setContentView(int layoutResID) {
LayoutInflater inflator = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setContentView(inflator.inflate(layoutResID, null));
}
public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
mWindow.setOnDismissListener(listener);
}
public void dismiss() {
mWindow.dismiss();
if (showListener != null) {
showListener.onDismiss();
}
}
public void setText(String text) {
mHelpTextView.setText(text);
}
public static interface ShowListener {
void onPreShow();
void onDismiss();
void onShow();
}
public void setShowListener(ShowListener showListener) {
this.showListener = showListener;
}
}
</code></pre>
</div>
Above is the magic code that will glue everything up and will create floating chrome style popups for you. There are few I would like you to focus on :<br />
<br />
<ol style="text-align: left;">
<li>Constructors are used to initialise view of the popup, along with additional secondary constructors initializing texts.</li>
<li>This also defines a static interface <i>ShowListener </i>which can be used to give callbacks.</li>
<li>To invoke popups <i>show()</i> should be called with an "Anchor" view.</li>
<li><i>show()</i> is the magic method where all calculations of screen alignment is done.</li>
</ol>
<div>
You have everything you need!</div>
<br />
<h3 style="text-align: left;">
Step 4 : Lets do some popups!</h3>
<div>
Lets stress test this popup we created, create a new layout xml file and save it in <b>res/layout/main.xml</b></div>
<div>
<b><br /></b></div>
<div>
<pre><code>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:weightSum="5" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:onClick="clicked"
android:text="Popup"
tools:context=".MainActivity" />
</LinearLayout>
</LinearLayout>
</code></pre>
</div>
<br />
This will create rows of buttons saying "Popup" and will call <i>clicked</i> method of referring activity when clicked. Considering MainActivity.java is your launcher activity lets update its source to<br />
<br />
<h4 style="text-align: left;">
MainActivity.java</h4>
<div>
<pre><code>
package com.example.chromestylehelppopups;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onResume() {
super.onResume();
}
public void clicked(View view) {
ChromeHelpPopup chromeHelpPopup = new ChromeHelpPopup(MainActivity.this,"Hello!");
chromeHelpPopup.show(view);
}
}
</code></pre>
</div>
And you are done! Wasn't that easy ? After you run this application, you should see something like this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a title="Creating Chrome Style Help Popups final output" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw7LGvEyuh5CLig1bdpbjnlNrquSRZRLt0c5uUFfLrS69nW6ZJ-anVMX9hocGBEg4qThKtmZITGgBQ-4-G02Na_oW27QtICKZYNF1AOkTHE4x2R3UWzUY6tbMNsI4f6XICnU6G7OuJLjI/s1600/final.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img title="Creating Chrome Style Help Popups final output" alt="Creating Chrome Style Help Popups final output" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw7LGvEyuh5CLig1bdpbjnlNrquSRZRLt0c5uUFfLrS69nW6ZJ-anVMX9hocGBEg4qThKtmZITGgBQ-4-G02Na_oW27QtICKZYNF1AOkTHE4x2R3UWzUY6tbMNsI4f6XICnU6G7OuJLjI/s400/final.png" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Don't forget to add comments :)</div>
<br />
You can also visit another post which describes <a title="Creating Google Now Cards on Android" href="http://shardulprabhu.blogspot.in/2012/09/google-now-cards-layout.html">Creating Google Now Cards on Android</a>.</div>Shardulhttp://www.blogger.com/profile/04615671114783206697noreply@blogger.com1