2

maybe some of you had try the new Google Calendar in material design. What I'm looking for is the "effect" or the way to make imageviews follow your scroll. It looks like a parallax effect but what I can find around are just libraries with parallax effect on header views. Can someone point me to the right direction? thanks!

iGio90
  • 3,251
  • 7
  • 30
  • 43

1 Answers1

1

AFAIK there is no library that does this however I did something like this a few months ago but it is very rudimentary and not dynamic at all.

First you need to extend ScrollView so you can get all the scrolling position that are only available to the scrollview class.

something like this

    public class TestScrollView extends ScrollView {

        private ScrollViewListener scrollViewListener = null;

        public interface ScrollViewListener {

            public void onScrollChanged(TestScrollView scrollView, int x, int y, int oldx, int oldy);

        }

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

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

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

        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);
            }
        }
    }

Next you have to extend ImageView to do all the parallax stuff. This may or may not work for you i dont know this was made for a specific case

public class ParallaxImageView extends ImageView {

    public static final float PARALLAX_COEFFICIENT = 0.65F;
    public static final float PROPERTY_IMAGE_INV_RATIO = 0.6666667F;
    private int intrinsicHeight = -1;
    Context context;

    public ParallaxImageView(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public ParallaxImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public ParallaxImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        init();
    }

    private void init(){
        post(new Runnable(){

            @Override
            public void run() {
                int i = (int)(PARALLAX_COEFFICIENT * (PROPERTY_IMAGE_INV_RATIO * getWidth()));
                getLayoutParams().height = i;
            }
        });
    }

    public void updateParallaxState()
    {
        int i = this.intrinsicHeight - getHeight();

        if (i == 0){
            return;
        }

        Rect localRect = getScreenLocation(this);
        int height = getHeight();
//        int j = getScreenSize().y + height;
//        float min = Math.min(1.0F, (localRect.top + height) / j);
//        float max = Math.max(min, 0.0F);
//        setScrollY((int)((max - 0.5F) * i));

        setScrollY((localRect.top-height-380)/8);
    }

    private Rect getScreenLocation(View paramView)
    {
        Rect localRect = new Rect();
        int[] arrayOfInt = new int[2];
        paramView.getLocationOnScreen(arrayOfInt);
        int i = getStatusbarHeight(paramView);
        localRect.set(arrayOfInt[0], arrayOfInt[1], arrayOfInt[0] + paramView.getWidth(), arrayOfInt[1] + paramView.getHeight());
        return localRect;
    }

    private int getStatusbarHeight(View paramView)
    {
        Rect localRect = new Rect();
        ((Activity)paramView.getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);
        return localRect.top;
    }
}

then in your activity implement the scrolllistener and the views

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TestScrollView scroll = (TestScrollView)findViewById(R.id.scroll);
    scroll.setScrollViewListener(this);

    i1 = (ParallaxImageView)findViewById(R.id.image1);
    i2 = (ParallaxImageView)findViewById(R.id.image2);
}

@Override
public void onScrollChanged(TestScrollView scrollView, int x, int y, int oldx, int oldy) {
    i1.updateParallaxState();
    i2.updateParallaxState();
}

then your layout would look something like this

<com.example.parallaximageview.app.TestScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/scroll">

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

         //other views

        <com.example.parallaximageview.app.ParallaxImageView
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:src="@drawable/camera_phone"
            android:scaleType="centerCrop"
            android:id="@+id/image2"/>

        //other views

    </LinearLayout>

</com.example.parallaximageview.app.TestScrollView>
tyczj
  • 71,600
  • 54
  • 194
  • 296
  • Hello, thanks for your method! Do you know if it's possible to achieve the same result with recyclerviews or listviews? – iGio90 Nov 22 '14 at 18:50
  • im sure its possible but it will be much much more difficult – tyczj Nov 22 '14 at 19:10