Paralax effect in app background

19,514

Solution 1

This is what you can do:

In your activity/fragment layout file specify 2 ScrollView's (say background_sv and content_sv).

<?xml version="1.0" encoding="utf-8"?>
<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" >

    <com.example.parallax.MyScrollView
        android:id="@+id/background_sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

            <ImageView
                android:id="@+id/parallax_bg"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="..." />
    </com.example.parallax.MyScrollView>

    <com.example.parallax.MyScrollView
        android:id="@+id/content_sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
        </LinearLayout>
    </com.example.parallax.MyScrollView>

</RelativeLayout>

Add a dummy view in the content scrollview of the height of the background and make it transparent. Now, attach a scroll listener to the content_sv. When the content scrollview is scrolled, call

mBgScrollView.scrollTo(0, (int)(y /*scroll Of content_sv*/ / 2f));

The existing API's doesn't have the support to get the scroll events. Hence, we need to create a Custom ScrollView, to provide the ScrollViewListener.

package com.example.parallax;

// imports;

public class MyScrollView extends ScrollView {

    public interface ScrollViewListener {
        void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy);
    }

    private ScrollViewListener scrollViewListener = null;

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

    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if(scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }
}

Here is the activity which hosts both the content ScrollView and background ScrollView

package com.example.parallax;

// imports;

public class ParallaxActivity extends Activity implements ScrollViewListener {

    private MyScrollView mBgScrollView;
    private MyScrollView mContentScrollView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        mBgScrollView = findViewById(R.id.background_sv);
        mContentScrollView = findViewById(R.id.content_sv);
        mContentScrollView.setOnScrollListener(this);
    }

    // this is method for onScrollListener put values according to your need
    @Override
    public void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy) {
        super.onScrollChanged(scrollView, x, y, oldx, oldy);
        // when the content scrollview will scroll by say 100px, 
        // the background scrollview will scroll by 50px. It will 
        // look like a parallax effect where the background is 
        // scrolling with a different speed then the content scrollview.
        mBgScrollView.scrollTo(0, (int)(y / 2f));
    }
}

Solution 2

I think the question is unclear, so this is not really an answer so much as an attempt to clarify with more detail than I could include in a comment.

My question is about what kind of parallax effect you want to achieve. Given these three examples (they are demo apps you can install from the Play Store), which if any has the type of parallax effect you want? Please answer in a comment.

Given an answer, we all will find it easier to help out. If you edit your question to include this information, it will be improved.

Solution 3

The following contains an example application published by the author of Paralloid:

https://github.com/chrisjenx/Paralloid/tree/master/paralloidexample

From the GitHub page under the 'Getting Started' section:

Layout

ScrollView

This is an example, please refer to the paralloidexample App for full code.

<FrameLayout ..>
<FrameLayout
        android:id="@+id/top_content"
            android:layout_width="match_parent"
            android:layout_height="192dp"/>

<uk.co.chrisjenx.paralloid.views.ParallaxScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

    <LinearLayout
        android:id="@+id/scroll_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingTop="192dp"/>

</uk.co.chrisjenx.paralloid.views.ParallaxScrollView>
</FrameLayout>

Fragment

Inside your onViewCreated() or onCreateView().

//...
FrameLayout topContent = (FrameLayout) rootView.findViewById(R.id.top_content);
ScrollView scrollView = (ScrollView) rootView.findViewById(R.id.scroll_view);
if (scrollView instanceof Parallaxor) {
        ((Parallaxor) scrollView).parallaxViewBy(topContent, 0.5f);
}
// TODO: add content to top/scroll content

Thats it!

Have a look at the Parallaxor interface for applicable Parallax methods.

Hope this helps!

Also, here is a link to Google's 'getting started' page for android.

Also, here is a link to a 'java tutorial for complete beginners'.

As well as link to some documentation about layouts, which 'define the visual structure for a user interface'.

That being said, you would use the layout to define what the interface looks like and use the subsequent example code to define what happens when you interact with it.

P.S. You can see the application in action here

Solution 4

Here is how it can be done using ScrollView and it's background image. I've committed the code in github.

You need to extend the ScrollView and Drawable classes.

  1. By default the ScrollView background height will be same as viewport height. To achieve the parallax effect, the background height should be larger and should be based on the ScrollView child height and the background scrolling factor we want to impose. Background scroll factor of 1 indicates, background height is same as ScrollView child height and hence background will scroll with same offset as the child scrolls. 0.5 indicates, background height is 0.5 times ScrollView child extended height and will scroll 50% slower compared to the child contents. This effectively brings the parallax scrolling effect.

Call following method from ScrollView constructor:

void init() {
    // Calculate background drawable size before first draw of scrollview
    getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            // Remove the listener
            getViewTreeObserver().removeOnPreDrawListener(this);

            mDrawable = (ParallaxDrawable) getBackground();

            if(mDrawable != null && mDrawable instanceof ParallaxDrawable) {
                // Get the only child of scrollview
                View child = getChildAt(0);
                int width = child.getWidth();
                // calculate height of background based on child height and scroll factor
                int height = (int) (getHeight() + (child.getHeight() - getHeight()) * mScrollFactor);
                mDrawable.setSize(width, height);
            }       

            return true;
        }       
    });     
}
  1. When ScrollView is scrolled, take into consideration the scroll offset while drawing the background. This basically achieves the parallax effect.

ParallaxScrollView:

protected void onScrollChanged(int x, int y, int oldX, int oldY) {
   if(mDrawable != null && mDrawable instanceof ParallaxDrawable) {
       // set the scroll offset for the background drawable.
       mDrawable.setScrollOffset(x*mScrollFactor, y*mScrollFactor);
   }
} 

ParallaxDrawable:

@Override
public void draw(Canvas canvas) {
    // To move the background up, translate canvas by negative offset
    canvas.translate(-mScrollXOffset, -mScrollYOffset);
    mDrawable.draw(canvas);
    canvas.translate(mScrollXOffset, mScrollYOffset);
}


protected void onBoundsChange(Rect bounds) {
    // This sets the size of background drawable.
    mDrawable.setBounds(new Rect(bounds.top, bounds.left, bounds.left + mWidth, bounds.top + mHeight));
}

Usage of ParallaxScrollView and ParallaxDrawable:

public class MyActivity extends Activity {

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

        final ParallaxScrollView scrollView = (ParallaxScrollView) findViewById(R.id.sv);
        ParallaxDrawable drawable = new ParallaxDrawable(getResources().getDrawable(R.drawable.bg));
        scrollView.setBackground( drawable, 0.2f );
    }
}

parallax_layout.xml:

<manish.com.parallax.ParallaxScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#fff"
                android:text="@string/text" />

            <View
                android:layout_width="match_parent"
                android:layout_height="5dp" />
            ...
        </LinearLayout>
</manish.com.parallax.ParallaxScrollView>

Solution 5

I use the ParallaxScroll library. Very easy to use, good samples and well documented.

Share:
19,514
Kamil
Author by

Kamil

Electrican by education Electronics engineer by hobby Programmer (some languages professionally, some by hobby) Windows Server admin - few years of experience Sorry for my grammar and spelling errors, feel free to correct them by editing my posts.

Updated on July 23, 2022

Comments

  • Kamil
    Kamil almost 2 years

    Im new in Android world. I want to put some parallax background effects in my app.

    How can I do it? How to approach to this in Android?

    Is there any productive way to create 2-3 layer parallax background? Is there some tool, or class in android API?

    Or maybe I have to modify background image location or margins "manually" in code?

    Im using API level 19.

    I have tried to understand Paralloid library, but this is too big to understand without any explanation. Im new to Android and Java, im not familiar with all Layouts and other UI objects, however I'm familiar with MVC.

    I started bounty, maybe someone can explain step by step how that library works.

  • Kamil
    Kamil over 9 years
    Well, I didn't knew that there is another free library. I will take a look at it, but don't think you will get +500 for 2 sentences :)
  • Mark Buikema
    Mark Buikema over 9 years
    It's a really nice library that's easy to use and I would appreciate if you awarded the bounty if it helped :)
  • Drew
    Drew over 9 years
    Also, if you review the documentation and still have questions, maybe we should go from there!
  • Kamil
    Kamil over 9 years
    It looks simple and clean, but... there is no onScroll event in ScrollView.
  • berserk
    berserk over 9 years
    @Kamil i was wondering who will get the bounty if this answer works :3
  • Kamil
    Kamil over 9 years
    @berserk It's hard to choose. I made parallax after combining informations from 2 answers...
  • Kamil
    Kamil over 9 years
    Ok. I think this is closest to simple and working parallax, but it is not complete. Before I reward you with bounty - please add information how to add onScrollChanged event. This works (Andy answer): stackoverflow.com/questions/3948934/…
  • Sagar Waghmare
    Sagar Waghmare over 9 years
    Yes, we need to get the scroll values based on the onScrollChanged event. Need to create CustomScrollView like done in the link you've specified.
  • Kamil
    Kamil over 9 years
    Can you edit your answer and add some code? I don't want to reward incomplete answer with "go there and find out".
  • Sagar Waghmare
    Sagar Waghmare over 9 years
    Added all the data required to make this parallax effect.
  • Himanshu Mori
    Himanshu Mori almost 8 years
    @SagarWaghmare you forgot to implement ScrollViewListener method.. already many times Kamil told you to add incomplete code.