Stelios Papamichail
Stelios Papamichail

Reputation: 1270

How to make an item in a ScrollView be positioned in the center of the screen

I have three CardView in a HorizontalScrollView and I want the middle one to be in the center of the screen (as if the user had swiped to get to it). How do I do that in XML or programmatically?

XML layout:

<HorizontalScrollView
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="16dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="16dp"
    android:scrollbars="none"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/culture_toolbar">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <androidx.cardview.widget.CardView
            android:id="@+id/one"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:layout_marginEnd="10dp"
            app:cardCornerRadius="12dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:src="@drawable/beach_bg_placeholder" />

        </androidx.cardview.widget.CardView>

        <androidx.cardview.widget.CardView
            android:id="@+id/two"
            android:layout_width="300dp"
            android:layout_height="300dp"
            app:cardCornerRadius="12dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:src="@drawable/beach_bg_placeholder" />

        </androidx.cardview.widget.CardView>

        <androidx.cardview.widget.CardView
            android:id="@+id/three"
            android:layout_width="300dp"
            android:layout_height="300dp"
            app:cardCornerRadius="12dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:src="@drawable/beach_bg_placeholder" />

        </androidx.cardview.widget.CardView>
    </LinearLayout>
</HorizontalScrollView>

This is the result I'm going for:

I want the upper half the mockup

Upvotes: 4

Views: 2681

Answers (5)

Pavlo Ostasha
Pavlo Ostasha

Reputation: 16699

For this behaviour you should use ViewPager or ViewPager2(which is basically a RecyclerView with SnapHelper included)

I will show how to do it with a regular ViewPager

so the pager settings for carousel should be like this

pager.apply{
            // Set current item to the middle page so we can fling to both
            // directions left and right
            currentItem = 1

            // Necessary or the pager will only have one extra page to show
            // make this at least however many pages you can see
            offscreenPageLimit = 3

            // Set margin for pages as a negative number, so a part of next and
            // previous pages will be showed
            // Calculate here a value you need
            pageMargin = -((3f / 4f) * App.screenWidth).toInt()
        }

While the adapted should implement ViewPager.PageTransformer

class CarouselPagerAdapter : PagerAdapter(), ViewPager.PageTransformer {

...

  companion object {
        val NO_SCALE = 1.0f
        val SMALL_SCALE_DOWN = 0.1f
        val DIFF_SCALE = NO_SCALE - SMALL_SCALE_DOWN

        val FULL_OPACITY = 255
        val LOW_OPACITY = 5
        val DIFF_OPACITY = FULL_OPACITY - LOW_OPACITY

        val NO_TRANSLATION = 0f
        val TRANSLATION_Y = 100f
        val DIFF_TRANSLATION_Y = TRANSLATION_Y - NO_TRANSLATION
    }

    override fun transformPage(page: View, position: Float) {
        val scalableLayout = page.item_child_wrapper
        val animatableLayout = page.child_name_wrapper
        var scale = NO_SCALE
        var opacity = FULL_OPACITY
        var translationY = NO_TRANSLATION
        if (position > 0) {
            scale -= position * DIFF_SCALE
            opacity -= (position * DIFF_OPACITY).toInt()
            translationY -= (position * DIFF_TRANSLATION_Y)
        } else {
            scale += position * DIFF_SCALE
            opacity += (position * DIFF_OPACITY).toInt()
            translationY += (position * DIFF_TRANSLATION_Y)
        }
        if (scale < 0) scale = 0f
        if (opacity < 0) opacity = 0
        if (opacity > 255) opacity = 255
        scalableLayout.setScale(scale)
        scalableLayout.setOpacity(opacity)
        animatableLayout.setScale(scale)
        animatableLayout.setTranslation(0f, translationY)
    }



}

This is my old code so it should be modernized somehow and it works also with opacity and transitions of elements - but I think you will figure how to use it.

Hope it helps.

Upvotes: 0

Sagar
Sagar

Reputation: 554

I had as same task like you have, to center the item in scroll view

I did if just changing in layour scroll view

Try to replace you scroll view with

https://github.com/yarolegovich/DiscreteScrollView

  <com.yarolegovich.discretescrollview.DiscreteScrollView
  android:id="@+id/picker"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  app:dsv_orientation="horizontal|vertical" />

Let me know if get success

Upvotes: 1

juancamilo87
juancamilo87

Reputation: 647

So I don't think you can do it in xml.

My suggestion would be to do it in code. So after setContentView() in an Activity or in onViewCreated() in a Fragment, you can measure the width of the whole scrollview, divide it by 2, and then use the method smoothScrollBy(int dx, int dy) of your horizontalScrollView, or scrollBy(int dx, int dy) if you don't it to be animated.

To get the width of the scrollview you can follow this answer. Just make sure you pass the correct units to the methods, either pixels, dps, etc.

If you need to transform the units then you can use something like this.

Upvotes: 1

AskNilesh
AskNilesh

Reputation: 69689

How do i do that in xml preferably?

AFAIK using XML only that is not possible

How to make an item in a ScrollView be positioned in the center of the screen

I would suggest that you should use carousel layout instead of using HorizontalScrollView

You can make carousel layout using ViewPager and using RecyclerView

Check out below good articles for carousel layout

Upvotes: 1

Mr. Tesla
Mr. Tesla

Reputation: 79

Have you tried to use a layout_gravity in the LinearLayout?

android:layout_gravity="center"

Before adding layout_gravity:center
See the result (Blueprint view): basic LinearLayout gravity

<LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

After adding layout_gravity:center
See the result (Blueprint view): LinearLayout with layout_gravity:center

<LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_gravity="center">

Upvotes: 1

Related Questions