13

I am creating images in which when scrolled up, the image should get enlarged and remaining images should get smaller. Similarly when second image pushed up, it should enlarge and show. I used accordion type but nothing works. I searched but couldn't find.

In IPhone, it has features but I couldn't find how to create for android. This is for

enter image description here

same effect to be implemented in android.

I used ScaleAnimation with hide and show of layouts to open where image been placed inside the layout. But that also didn't work.

if(openLayout == panel1){
    panel1.startAnimation(new ScaleAnimToHide(1.0f, 1.0f, 1.0f, 0.0f, 200, panel1, true));
}

Can someone help me to solve this issue?

Thanks in advance!!

N Sharma
  • 33,489
  • 95
  • 256
  • 444
Shadow
  • 6,864
  • 6
  • 44
  • 93

2 Answers2

9

I have created a basic custom view which replicates this behaviour, it's not completely the same but I think it's close enough for now, if it needs to be exactly the same this can be quickly achieved by modifying the updateChildViews() method. I wrote this class in 20 minutes so it's far from perfect, for a production ready solution some additional work has to be done. Generally this solution works with all kinds of child views, but to replicate the exact behaviour use an ImageView as background for your child views and set this property on the ImageViews:

android:scaleType="centerCrop"

Problems I see with my solution in it's current state:

  • Only works in vertical orientation
  • No view recycling.
  • Should be derived from AdapterView and not LinearLayout.

Anyway that's how it looks so far:

enter image description here

Here is the source code:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

public class Accordion extends LinearLayout {

    private static final String LOG_TAG = Accordion.class.getSimpleName();

    private double scrollProgress = 0.0;
    private double topViewScaleFactor = 2.0;
    private double collapsedViewHeight = 200.0;
    private double expandedViewHeight = 700.0;
    private double scrollProgressPerView = expandedViewHeight;

    private final ScrollTouchListener touchListener = new ScrollTouchListener() {
        @Override
        protected void onScroll(float x, float y) {
            scrollProgress += y;
            if(scrollProgress < 0.0) {
                scrollProgress = 0.0;
            }

            int viewCount = getChildCount();
            double maxScrollProgress = (viewCount - 1) * scrollProgressPerView + 1;
            if(scrollProgress > maxScrollProgress) {
                scrollProgress = maxScrollProgress;
            }

            Log.i(LOG_TAG, String.format("Scroll Progress: %f", scrollProgress));

            updateChildViews();
        }
    };

    public Accordion(Context context) {
        super(context);

        this.setOnTouchListener(this.touchListener);
    }

    public Accordion(Context context, AttributeSet attrs) {
        super(context, attrs);

        this.setOnTouchListener(this.touchListener);
    }

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

        this.setOnTouchListener(this.touchListener);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        updateChildViews();
    }

    private void updateChildViews() {
        int viewCount = getChildCount();
        double progress = scrollProgress;
        double overflow = 0;
        for(int i = 0; i < viewCount; i++) {
            View child = getChildAt(i);
            if(child != null) {
                if(progress >= scrollProgressPerView) {
                    progress -= scrollProgressPerView;
                    child.setVisibility(View.GONE);
                    setChildHeight(child, 0);
                } else if (progress > 0) {
                    setChildHeight(child, expandedViewHeight - progress);
                    overflow = progress;
                    child.setVisibility(View.VISIBLE);
                    progress = 0;
                } else {
                    if(overflow > 0) {
                        double height = collapsedViewHeight + overflow;
                        if(height > expandedViewHeight) {
                            height = expandedViewHeight;
                        }
                        setChildHeight(child, height);
                        overflow = 0;
                    } else {
                        setChildHeight(child, i > 0 ? collapsedViewHeight : expandedViewHeight);
                    }
                    child.setVisibility(View.VISIBLE);
                }
            }
        }
    }

    private void setChildHeight(View child, double height) {
        child.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)height));
    }

    private static abstract class ScrollTouchListener implements OnTouchListener {

        private static final String LOG_TAG = ScrollTouchListener.class.getSimpleName();

        private boolean scrolling = false;
        private float x = 0;
        private float y = 0;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    x = event.getX();
                    y = event.getY();
                    scrolling = true;
                    return true;

                case MotionEvent.ACTION_UP:
                    scrolling = false;
                    return true;

                case MotionEvent.ACTION_MOVE:
                    if (scrolling) {
                        float newX = event.getX();
                        float newY = event.getY();

                        float difX =  x - newX;
                        float difY =  y - newY;
                        onScroll(difX, difY);

                        x = newX;
                        y = newY;
                    }
                    return true;

                default:
                    return false;
            }
        }

        protected abstract void onScroll(float x, float y);
    }
}

To use it just put it in a layout like this:

<at.test.app.Accordion xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">

    <ImageView android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:scaleType="centerCrop"
               android:src="@drawable/alpen"/>

    <ImageView android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:scaleType="centerCrop"
               android:src="@drawable/alpen"/>

    <ImageView android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:scaleType="centerCrop"
               android:src="@drawable/alpen"/>

    <ImageView android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:scaleType="centerCrop"
               android:src="@drawable/alpen"/>

</at.test.app.Accordion>

If you have any additional questions feel free to ask!

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
0

I think if the container you are using is a ListView, then following must be useful.Just need to detect the center element of the list view, and apply the zooming effect to the image in that row.Following is the code that can be used to implement this strategy:

int visibleChildCount = (listView1.getLastVisiblePosition() - listView1.getFirstVisiblePosition()) + 1;

In your getView() method:
if(position==visibleChildCount/2)
{
 //Center Element
 //Apply the Transition Effect From the XML files to the Image to Grow.
}
Parth Kapoor
  • 1,494
  • 12
  • 23
  • I think trying to get a ListView to act this way is much more difficult than writing a custom view. This effect is not as simple as it might seem you won't get far with just applying an animation to some views. – Xaver Kapeller Mar 18 '14 at 11:14
  • Well Good Luck then... and please post any leads or thoughts that you have in this regards so that I can also be on same page with you. – Parth Kapoor Mar 18 '14 at 11:45
  • I don't really know what you mean, but you can take a look at my answer. It's a complete working example. – Xaver Kapeller Mar 18 '14 at 12:02
  • @XaverKapeller excellent. i have one doubt.what it means should derived from AdapterView?directly extending as linearlayout and in the constructor, i can use like this by adding xml? LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mView = inflater.inflate(R.layout.main, this, false) – Shadow Mar 18 '14 at 14:34
  • Please explain better, and don't put something like that in the comments, edit your question. – Xaver Kapeller Mar 18 '14 at 14:35
  • i can't get this line.Should be derived from AdapterView and not LinearLayout. @XaverKapeller – Shadow Mar 18 '14 at 14:38
  • 1
    My example is currently extending LinearLayout, but that is not optimal, especially if a big number of child views are supposed to be displayed. For a perfect solution the custom view should extend AdapterView and implement proper view recycling. But for most cases my custom view should already be a pretty good solution. – Xaver Kapeller Mar 18 '14 at 14:40