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.
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 Views in your application.
You can pull / download entire Eclipse project source from my Github repo :
Or stick through to see how to create one of these.
Step 1 : Creating Resources Required
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
Background:
<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>
This will define a new shape drawable, save this in
res/drawable/blue_bg.xml
Floating Animation
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.
<?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>
Save it as
res/anim/float_anim.xml.
Step 2 : Popup definition files
Now lets start with popup declarations. To match look and feel, lets define a layout, composing an up arrow (ImageView) , text (TextView) and down arrow (ImageView).
Popup layout
<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>
Save this layout as
res/layout/popup.xml
You will have to import 2 arrow images one pointing up and other pointing down to compile this.
This layout is also referring to an external style definition, which we will create next
<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>
This wil go into
res/values/styles.xml.
Step 3 : ChromeHelpPopup.java
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;
}
}
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 :
- Constructors are used to initialise view of the popup, along with additional secondary constructors initializing texts.
- This also defines a static interface ShowListener which can be used to give callbacks.
- To invoke popups show() should be called with an "Anchor" view.
- show() is the magic method where all calculations of screen alignment is done.
You have everything you need!
Step 4 : Lets do some popups!
Lets stress test this popup we created, create a new layout xml file and save it in res/layout/main.xml
<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>
This will create rows of buttons saying "Popup" and will call
clicked method of referring activity when clicked. Considering MainActivity.java is your launcher activity lets update its source to
MainActivity.java
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);
}
}
And you are done! Wasn't that easy ? After you run this application, you should see something like this.
Don't forget to add comments :)
You can also visit another post which describes
Creating Google Now Cards on Android.