107

I'm trying to create a semi-transparent demo screen that is launched only when a user first installs my application. Here's an example from the Pulse News app:

Galaxy Nexus

Example screenshot from Pulse News on Galaxy Nexus

Nexus One

enter image description here

Instead of a 'tap-to-dismiss' feature, I want the user to be able to swipe through a couple of such transparent demo pages.

For my first attempt, I modified a sample from the ViewPagerIndicator library. I used semi-transparent PNGs in ImageViews inside each of the view pager's fragments. I then launched this as a 'demo activity' in the onCreate method of my 'main activity'.

Problem: The 'main activity' could not be seen in the background - instead it was just black. I tried the solutions here, but that didn't fix the problem.

Is there a better approach to creating something like this, or am I on the right track?

I also had another related question which depends on how this is implemented. I'm trying to overlay text and arrows such that they point at particular UI components in the background. By using a PNG that has the text and arrows, it's likely that it will not scale properly on different devices. I.e., the arrows may not necessarily point to the correct UI component in the background. Is there a way to tackle this problem as well?

Thanks!

Here's my code for the first attempt:

DemoActivity.java

public class DemoActivity extends FragmentActivity {
    DemoFragmentAdapter mAdapter;
    ViewPager mPager;
    PageIndicator mIndicator;

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

        mAdapter = new DemoFragmentAdapter(getSupportFragmentManager());

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        //mPager.setAlpha(0);

        UnderlinePageIndicator indicator = (UnderlinePageIndicator)findViewById(R.id.indicator);
        indicator.setViewPager(mPager);
        indicator.setFades(false);
        mIndicator = indicator;
    }

}

DemoFragmentAdapter.java

class DemoFragmentAdapter extends FragmentPagerAdapter {
    protected static final int[] CONTENT = new int[] { R.drawable.demo1, R.drawable.demo2, R.drawable.demo3, R.drawable.demo4};

    private int mCount = CONTENT.length;

    public DemoFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return DemoFragment.newInstance(CONTENT[position % CONTENT.length]);
    }

    @Override
    public int getCount() {
        return mCount;
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    } }

DemoFragment.java

public final class DemoFragment extends Fragment {
    private static final String KEY_CONTENT = "TestFragment:Content";

    public static DemoFragment newInstance(int content) {
        DemoFragment fragment = new DemoFragment();
        fragment.mContent = content;
        return fragment;
    }

    private int mContent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
            mContent = savedInstanceState.getInt(KEY_CONTENT);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        ImageView image = new ImageView(getActivity());
        image.setBackgroundResource(mContent);

        LinearLayout layout = new LinearLayout(getActivity());
        layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        layout.setGravity(Gravity.CENTER);
        layout.addView(image);

        return layout;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(KEY_CONTENT, mContent);
    }
}
Community
  • 1
  • 1
Gautam
  • 4,006
  • 3
  • 32
  • 37

8 Answers8

80

Put your demo info in a different activity and give it the following theme.

<style name="Transparent" parent="@android:style/Theme.NoTitleBar">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>      
    <item name="android:backgroundDimEnabled">false</item>
</style>

If you're using ActionBarSherlock change parent to @style/Theme.Sherlock.

This will give you a transparent activity, so you will be able to see the activity below it.

Now I'm guessing you want a translucent background too.

In the xml layout (of your transparent activity) add:

android:background="#aa000000" 

The last 6 digits define the color: 000000 is black.

The first 2 define the opacity: 00 is 100% transparent, ff is 100% opaque. So choose something in between.

Benito Bertoli
  • 25,285
  • 12
  • 54
  • 61
  • 1
    Thanks for the answer! This is pretty much what I ended up doing, after a lot of [trial and error](http://stackoverflow.com/questions/12031233/android-viewpager-not-filling-screen-on-galaxy-nexus-only). I'm still curious as to how the Pulse demo screen is able to 'reposition' the overlayed content in the right places, even on different screen sizes - see the updated screenshots. Any ideas? – Gautam Aug 31 '12 at 07:30
  • 2
    In your first activity find the view you wish to point to (`findViewById`). Then get its position relative to the root layout using [this method](http://stackoverflow.com/a/3621042/1117415). Send position to overlay activity in the intent. Do proper alignment. – Benito Bertoli Aug 31 '12 at 07:51
  • 2
    Or use `View.getLocationOnScreen(int[] location)` or `View.getLocationInWindow(int[] location)`. I'm not sure which one is better. – Benito Bertoli Aug 31 '12 at 08:01
  • @Gautam: "Any ideas?" -- for Pulse, this is a matter of putting one image in the upper-left corner, another image centered, and a third image in the lower-right corner. A dozen or so lines of XML, based on a `RelativeLayout`, would suffice. – CommonsWare Aug 31 '12 at 23:40
  • I tried the theme with both parents with a simple activity and a SherlockActivity but they both appear with a black background., not transparent and I can't see the activity behind. Any advice ? And both of them had a contentview with the background set. I can see their widgets but the activity's background is just black and opaque. – Snicolas Sep 01 '12 at 15:34
  • @Snicolas Add a theme to your styles file, see my answer below – powder366 Oct 31 '13 at 16:37
  • – powder366 Nov 01 '13 at 09:30
  • this is the best solution to not add libraries or complicate your existing activities too much. +1. – rupps Apr 01 '14 at 19:43
  • 1
    This worked for me, but I had problems in my activities doing extend Activity. So in order to use AppCompatActivity I defined the style like this: – Jose Q Jan 31 '19 at 22:10
65

Have you looked at ShowcaseView? https://github.com/Espiandev/ShowcaseView.

Using this:

View showcasedView = findViewById(R.id.view_to_showcase);
ViewTarget target = new ViewTarget(showcasedView);
ShowcaseView.insertShowcaseView(target, this, R.string.showcase_title, R.string.showcase_details);
Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Nik
  • 2,380
  • 2
  • 16
  • 15
11

Pulse is using a RelativeLayout with four ImageView's and four TextView's. The text in the screen shot is all TextView's with their own custom font.

In your Manifest add the following to your Activity:

android:theme="@style/Theme.Transparent">

In to your outer RelativeLayout add:

android:background="#aa000000"

To your styles.xml file:

<style name="Theme.Transparent" parent="android:Theme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>    

An example how to program the custom font you can find at:

https://github.com/commonsguy/cw-android/tree/master/Fonts/FontSampler/

The layout from the Hierarchy Viewer looks like this (the red box is the RelativeLayout container):

enter image description here

powder366
  • 4,351
  • 7
  • 47
  • 79
6
setContentView(R.layout.sample_main);
showOverLay();

private void showOverLay(){

    final Dialog dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);

    dialog.setContentView(R.layout.transparent);

    RelativeLayout layout = (RelativeLayout) dialog.findViewById(R.id.transparent);

    layout.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View arg0) {

            dialog.dismiss();

        }

    });

    dialog.show();

}
andrewsi
  • 10,807
  • 132
  • 35
  • 51
Ravikiran
  • 2,413
  • 5
  • 25
  • 30
  • exactly what i looking for simple and straight forward ,and easily method call without controlling or stacking activities . thanks – Abhishek Garg Dec 04 '18 at 12:24
5

For this you need to create help layout in bottom of your main layout ex:(structure)

<Parent layout>

<Layout 1>(Linear,Relative,....)
  Main layout
  your view...
</Layout 1>

<Layout help>
  set #70000000 as background of this layout 
  #70(transparent range can change) 000000(black)
  and height and width as fillparent
</Layout help>

</Parent layout>
Surendar D
  • 5,554
  • 4
  • 36
  • 38
2

Wrap your main layout in a RelativeLayout, then add a second layout to that, something like:

<RelativeLayout
    .... >

    <LinearLayout
        .... >

        <!-- Contents of your main layout -->

    </LinearLayout>

    <LinearLayout
        ....
        android:background="#44000000" > <!-- This is alpha 68/255, black -->

        <!-- Contents of your overlay layout -->

    </LinearLayout>

</RelativeLayout>

I believe the overlay layout goes below the main layout in the XML file (if memory serves). You can then make your own layout, ViewFlipper, whatever you want within this second layout.

Cat
  • 66,919
  • 24
  • 133
  • 141
  • 1
    Thanks for your response! I tried this and it does seem to work. However, there's one issue - the content in the overlay layout doesn't cover over the ActionBar or the ActionBar tabs I have in my activity. – Gautam Aug 18 '12 at 01:09
  • You added the `RelativeLayout` to the `demo_activity.xml` file? And is `DemoActivity` your main (first) `Activity`? – Cat Aug 18 '12 at 02:01
  • Well 'DemoActivity' was my attempt to create a transparent activity that would do the same thing. 'MainActivity' is the activity that I want underneath in the background. So I wrapped the layout for 'MainActivity', i.e. 'main_activity.xml' with the 'RelativeLayout' like you mentioned and also inserted the transparent 'LinearLayout'. The problem is, all of the content in 'main_activity.xml' is shown below the 'ActionBar' and any of its navigation tabs. – Gautam Aug 18 '12 at 02:10
1

Make a new Activity (say Tutorial).

Go to your Activity's layout xml file (activity_tutorial). Under the parent layout, add "android:background= #000" and "android:alpha= "0.5"

<RelativeLayout 
    
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
                
                
    tools:context=".Tutorial_Activity" 
    android:background="#000"
    android:alpha="0.5">
  ..................................................
  ....................................................
  .............................................
  ...............................................
  
  </RelativeLayout>

Now, go to application manifest file and under your tutorial activity add attribute android:theme="@android:style/Theme.Translucent.NoTitleBar">

<application>
 .........................................
..........................................
....................................
..........................................

<activity
            android:name="com.aird.airdictionary.Tutorial_Activity"
            android:label="@string/title_activity_tutorial"
            
          android:theme="@android:style/Theme.Translucent.NoTitleBar">
  
        </activity>
    </application>

</manifest>

Thats it, now run this activity on top of any other activity and you can get the desired results. Customize, add text, imageviews and other stuff to get your desired tutorial screen. Pretty sure that you can make a viewpager work with this technique.

0

You could just check out the Android launcher code, as they do it. I do not know there implementation.

If it was me I would (if just a simple overlay) so you dont screw with your layout for your application, just create your overlay layout, and attach it over ur application layout by adding it directly with your activities WindowManager. Could be as simple as adding a ImageView to the WindowManager, listen for touches on the ImageView, or have a timeout to to remove the ImageView from your Window.

Jug6ernaut
  • 8,219
  • 2
  • 26
  • 26