Code Example

Android Elastic ScrollView Snippets

Learn about Elastic ScrollView in android via simple code snippets and examples.

1. How to create an Elastic ScrollView in android.

Learn how to create an elastic scrollview in android without using any third party library.

This is a sample android app implementing elastic scrollView.

This example will help you learn the following concepts:

  1. We will create a custom layout based on the FrameLayout
  2. Create a custom NestedScrollView by extending the NestedScorllView class
  3. Create a custom ScrollView by extending the ScrollView class
  4. We create an elastic scrollview then use the created widget in our layout.

Here are the demo screenshots of what is created:

How to create an Elastic ScrollView in android.

This example will comprise the following files:

  • Behaviour.java
  • CustomLayout.java
  • CustomNestedScrollview.java
  • CustomScrollView.java
  • MainActivity.java

Step 1: Create Project

  1. Open your AndroidStudio IDE.
  2. Go to File-->New-->Project to create a new project.

Step 2: Dependencies

No special dependency is needed.

Step 3: Design Layouts

*(a). activity_main.xml

Create a file named activity_main.xml and design it as follows:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.bye.hey.coordinator.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <com.bye.hey.coordinator.CustomLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#32d541"
        android:paddingTop="8dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:id="@+id/aa"
            android:layout_width="match_parent"
            android:layout_height="164dp"
            android:layout_marginTop="8dp"
            android:background="@color/colorAccent"
            android:orientation="horizontal"
            android:scaleX="0.7"
            android:scaleY="0.7">

            <View
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_gravity="center_vertical"
                android:layout_margin="16dp"
                android:background="#f4f4f4" />

            <View
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_gravity="center_vertical"
                android:layout_margin="16dp"
                android:background="#3277d3" />

            <View
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_gravity="center_vertical"
                android:layout_margin="16dp"
                android:background="#fa7af6" />

        </LinearLayout>

        <com.bye.hey.coordinator.CustomScrollView
            android:id="@+id/sss"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

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

                <View
                    android:layout_width="match_parent"
                    android:layout_height="300dp"
                    android:layout_marginBottom="8dp"
                    android:background="@color/colorPrimaryDark" />

                <View
                    android:layout_width="match_parent"
                    android:layout_height="300dp"
                    android:layout_marginBottom="8dp"

                    android:background="@color/colorPrimaryDark" />

                <View
                    android:layout_width="match_parent"
                    android:layout_height="300dp"
                    android:layout_marginBottom="8dp"

                    android:background="@color/colorPrimaryDark" />

            </LinearLayout>
        </com.bye.hey.coordinator.CustomScrollView>
    </com.bye.hey.coordinator.CustomLayout>
</android.support.design.widget.CoordinatorLayout>

*(b). content_main.xml

Create a file named content_main.xml and design it as follows:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.bye.hey.coordinator.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Step 4: Write Code

Write Code as follows:

(a). Behaviour.java

Create a file named Behaviour.java

Create a Behaviour class by extending the CoordinatorLayout.Behavior<NestedScrollView>

public class Behaviour extends CoordinatorLayout.Behavior<NestedScrollView> {

Override the following methods:

@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return true;
}

@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
if (dyUnconsumed < 0) {
child.offsetTopAndBottom(-dyUnconsumed);
totaloffset = totaloffset + dyUnconsumed;
}
}

@Override
public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View target, int type) {
super.onStopNestedScroll(coordinatorLayout, child, target, type);
}

Here is the full code

package com.bye.hey.coordinator;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.view.View;

public class Behaviour extends CoordinatorLayout.Behavior<NestedScrollView> {
    private int totaloffset;

    public Behaviour(Context context, AttributeSet attrs) {

    }
    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        return true;
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        if (dyUnconsumed < 0) {
            child.offsetTopAndBottom(-dyUnconsumed);
            totaloffset = totaloffset + dyUnconsumed;
        }
    }

    @Override
    public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull NestedScrollView child, @NonNull View target, int type) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type);
    }
}

(b). CustomLayout.java

Create a file named CustomLayout.java

Extend the FrameLayout class to create a custom layout

public class CustomLayout extends FrameLayout {

Here is the full code

package com.bye.hey.coordinator;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;

public class CustomLayout extends FrameLayout {
    private static final String TAG = CustomLayout.class.getName();
    private ScrollView scrollview;
    private float yPrec;
    private int mTouchSlop;
    private boolean mIsScrolling;
    private float dX, dY;
    private float currentY;
    private boolean isAnimating;
    private LinearLayout backview;

    public CustomLayout(@NonNull Context context) {
        super(context);
        init();
    }

    public CustomLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        ViewConfiguration vc = ViewConfiguration.get(getContext());
        mTouchSlop = vc.getScaledTouchSlop();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                yPrec = ev.getY();
                dY = scrollview.getY() - ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float dy = ev.getY() - yPrec;
                if (dy < mTouchSlop) {
                    Log.d(TAG, "onInterceptTouchEvent: scrolling down");
                } else {
                    Log.d(TAG, "onInterceptTouchEvent: scrolling up");
                    if (scrollview.getScrollY() == 0) {
                        Log.d(TAG, "onInterceptTouchEvent: scrollview is at the top");
                        return true;
                    }
                }
                break;
        }

        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: called");

        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                Log.d(TAG, "onTouchEvent: action_move");
                dragView(event);
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "onTouchEvent: action_up");
                reboundView();
                break;
        }
        return super.onTouchEvent(event);

    }

    private void reboundView() {
        Log.d(TAG, "reboundView: " + scrollview.getY());
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(scrollview.getY(), 0);
        valueAnimator.setDuration(450);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                isAnimating = false;
                backview.setScaleX(0.7f);
                backview.setScaleY(0.7f);
                super.onAnimationEnd(animation);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                isAnimating = true;
                super.onAnimationStart(animation);
            }
        });
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                scrollview.setY((Float) valueAnimator.getAnimatedValue());
                float a = (float) valueAnimator.getAnimatedValue();
                backview.setScaleX((float) (((0.3 / 400.0) * (a)) + 0.7));
                backview.setScaleY((float) (((0.3 / 400.0) * (a)) + 0.7));
            }
        });
        valueAnimator.start();
    }

    private void dragView(MotionEvent event) {
        if ((event.getRawY() + dY) < 400)
            scrollview.setY(event.getRawY() + dY);

        if ((event.getRawY() + dY) > 0 && (event.getRawY() + dY) < 400) {
            backview.setScaleX((float) (((0.3 / 400.0) * (event.getRawY() + dY)) + 0.7));
            backview.setScaleY((float) (((0.3 / 400.0) * (event.getRawY() + dY)) + 0.7));
        }

    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        if (child.getId() == R.id.sss) {
            scrollview = ((ScrollView) child);

        } else if (child.getId() == R.id.aa) {
            backview = ((LinearLayout) child);
        }
    }

}

(c). CustomNestedScrollview.java

Create a file named CustomNestedScrollview.java

Extend the NestedScrollView class as shown below:

public class CustomNestedScrollview extends NestedScrollView {

Provide a constructor that takes in aContext object

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

Override the onStartNestedScroll():

@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return true;
}

Here is the full code

package com.bye.hey.coordinator;

import android.content.Context;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomNestedScrollview extends NestedScrollView {
    public CustomNestedScrollview(Context context) {
        super(context);
    }
    public CustomNestedScrollview(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return true;
    }

}

(d). CustomScrollView.java

Create a file named CustomScrollView.java

Extend the ScrollView class to create a custom ScrollView:

public class CustomScrollView extends ScrollView {

Provide constructors

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

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

public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

Here is the full code

package com.bye.hey.coordinator;

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

public class CustomScrollView extends ScrollView {
    public CustomScrollView(Context context) {
        super(context);
    }

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

    public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

}

(e). MainActivity.java

Create a file named MainActivity.java

Here is the full code

package com.bye.hey.coordinator;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Run

Simply copy the source code into your Android Project,Build and Run.

Reference

  1. Download code or Browse here.
  2. Follow code author.

Read More.

Related Posts