6

When I scroll within my Android scrollview, it scrolls down as it should.

But I'd like the image within the imageview to anchor to the centre. So you always see the face of the person in the image as you scrolling up.

So far I have not been able to accomplish this

A similar effect is created in the image below:

enter image description here

Stockguy image:

enter image description here

My code so far (which so far doesn't accomplish this):

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fillViewport="true"
    android:scrollbars="none"
    android:background="#FAFAFA"
    android:id="@+id/cScrollview"
    >

<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="1100dp"
    tools:context=".MainActivity"
    android:id="@+id/CRLayout">

        <ImageView
            android:layout_gravity="center"
            android:adjustViewBounds="true"
            android:layout_width="601dp"
            android:layout_height="250dp"
            android:paddingTop="0dp"
            android:paddingLeft="0dp"
            android:paddingRight="0dp"
            android:scaleType="centerCrop"
            android:id="@+id/contactPic"
            android:src="@drawable/stockguy"/>

            ....


            </RelativeLayout>
</ScrollView>
Ruchir
  • 1,018
  • 7
  • 17
  • 3
    [How to do the new PlayStore parallax effect](http://stackoverflow.com/questions/25461014/how-to-do-the-new-playstore-parallax-effect) – Kaushik Jan 20 '15 at 10:57
  • Are you saying that you already implemented the functionality where on scrolling down the action bar start appearing and the title get smaller. and the things that not yet working is the image thing? – hasan Jan 20 '15 at 10:57
  • So far I have not been able to accomplish this (added to question) –  Jan 20 '15 at 10:59
  • you diffenetly need to know the current user scroll position. no other solution. you don't need the relative layout. on scroll change change the value of image view top margin. keep scale type set to centre crop. – hasan Jan 20 '15 at 11:09
  • What does scroll position have to do with it? –  Jan 20 '15 at 11:10
  • you may need to change top and bottom margin together with the same value. anyway you are going to need scroll position to achieve the other behaviours. thats fore sure. – hasan Jan 20 '15 at 11:13
  • 1
    on scrolling image view will move to top and start disappearing. you need to push the image view to bottom with value equal to scroll position divided by two. or as alternative set top and bottom margin with the same value which is equal to scroll position divided by two. – hasan Jan 20 '15 at 11:21
  • @LivingFeature you just go with fadingactionbar lib i think you can achieve your goal if use this lib.... – duggu Jan 20 '15 at 11:32
  • Move the image out of the scroll, or use framelayout – Mal Jan 20 '15 at 12:18
  • Why not just change the origin with a custom affine matrix for the animation? – Lorne Laliberte Jan 29 '15 at 23:10

3 Answers3

2

To achieve parallax effect like on image you posted try following code. It is a very simple way.

Layout:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/rlWrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/ivContactPhoto"
            android:layout_width="match_parent"
            android:layout_height="@dimen/contact_photo_height"
            android:scaleType="centerCrop"
            android:src="@drawable/stockguy" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/contact_photo_height"
            android:layout_marginTop="250dp">

            <!-- Other Views -->

        </LinearLayout>

    </RelativeLayout>
</ScrollView>

LinearLayout's top margin is equal to the ImageViews's height.

Listening scroll position of the ScrollView and changing position of ImageView:

@Override
protected void onCreate(Bundle savedInstanceState) {
    <...>

    mScrollView = (ScrollView) findViewById(R.id.scrollView);
    mPhotoIV = (ImageView) findViewById(R.id.ivContactPhoto);
    mWrapperRL = (RelativeLayout) findViewById(R.id.rlWrapper);

    mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ScrollPositionObserver());

    <...>
}

private class ScrollPositionObserver implements ViewTreeObserver.OnScrollChangedListener {

    private int mImageViewHeight;

    public ScrollPositionObserver() {
        mImageViewHeight = getResources().getDimensionPixelSize(R.dimen.contact_photo_height);
    }

    @Override
    public void onScrollChanged() {
        int scrollY = Math.min(Math.max(mScrollView.getScrollY(), 0), mImageViewHeight);

        // changing position of ImageView
        mPhotoIV.setTranslationY(scrollY / 2);

        // alpha you can set to ActionBar background
        float alpha = scrollY / (float) mImageViewHeight;
    }
}

Hope it will help.

erakitin
  • 11,437
  • 5
  • 44
  • 49
1

I'd take a different approach with that.

Try building your layout based on the following snippet:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
<ImageView
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:background="#00FF00"
    android:scaleType="centerCrop"
    android:layout_height="200dp"/>
<FrameLayout
    android:id="@+id/content"
    android:layout_below="@+id/image"
    android:background="#FF0000"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</RelativeLayout>

Using the GestureDetector.SimpleOnGestureListeneryou can detect when the user scrolls on the content layout and update the image size and alpha accordingly to get the effect you describe.

Muzikant
  • 8,070
  • 5
  • 54
  • 88
1

I would implement this using a scroll callback on the ScrollView, this doesn't exist by default but is easy to create yourself by extending ScrollView:

public class UpdatingScrollView extends ScrollView {

    private OnScrollChangedListener mScrollChangedListener;

    public interface OnScrollChangedListener {
        public void onScrollChanged(int x, int y, int oldx, int oldy);
    }

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

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

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

    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        mScrollChangedListener = listener;
    }

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

So replace ScrollView in your layout with com.your.package.UpdatingScrollView.

In your Fragment/Activity where the UpdatingScrollView is defined you set the scroll listener and update the bottom margin of the image based on the scroll offset. For every 2 pixels the ScrollView has scrolled you'll want to update the bottom margin by -1 pixel which will make the image move up the screen at half the rate of the rest of the content.

So something like this:

scrollView.setOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged(int x, int y, int oldx, int oldy) {
        // I think y will be negative when scrolled
        if(y >= -image.getHeight()) {
            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) image.getLayoutParams();
            lp.setMargins(0, 0, 0, y / 2);
            image.setLayoutParams(lp);
        }
    }
});
darnmason
  • 2,672
  • 1
  • 17
  • 23