3

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

AskNilesh
  • 58,437
  • 15
  • 99
  • 129
  • 2
    You should just use a `ViewPager`, or `RecyclerView` with `SnapHelper` – Ernest Zamelczyk Aug 05 '19 at 06:43
  • O, you fancy? :-) – portfoliobuilder Sep 17 '19 at 23:14
  • @ErnestZamelczyk i managed to create the same layout with a `ViewPager` and an `Adapter` for it and i now have the required functionality. My only issue though, is that i can't seem to be able to make the other 2 `CardView` objects show on the sides like in the image. Right now i can only see the selected one and i have to scroll to see any part of the other two cards. Any ideas? – Stelios Papamichail Sep 20 '19 at 13:03
  • 1
    Maybe try [that solution](https://stackoverflow.com/a/23356010/4745241). But honestly I think it would work way better with recyclerview with pagersnaphelper. – Ernest Zamelczyk Sep 21 '19 at 16:29
  • Thank you very much, that link worked perfectly. Would you mind posting all of our conversation here as an answer with the links so that i can select it and award the rep? – Stelios Papamichail Sep 22 '19 at 11:33
  • @ErnestZamelczyk the bounty expires tomorrow and i'd like to give it to you since you were correct and so helpful. Please post your answer – Stelios Papamichail Sep 23 '19 at 13:42
  • 1
    oops. Didn't notice your comment until now. Too bad :p I'm glad that you got it working though. That's all that counts :) – Ernest Zamelczyk Sep 24 '19 at 19:16

5 Answers5

1

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">
walnut
  • 20,566
  • 4
  • 18
  • 54
Mr. Tesla
  • 29
  • 4
1

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

AskNilesh
  • 58,437
  • 15
  • 99
  • 129
1

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.

juancamilo87
  • 429
  • 3
  • 10
  • I tried doing `val scrollView:HorizontalScrollView = findViewById(R.id.horizontalScrollView) scrollView.smoothScrollBy(scrollView.getChildAt(1).width/2,0)` but it says that `getChildAt(1)` is `null`. Maybe because it is inside the Linear Layout? – Stelios Papamichail Sep 19 '19 at 19:23
  • You need to do `getChildAt(0)` since the only view inside the layout is the linear layout. – juancamilo87 Sep 21 '19 at 11:12
  • I tried that right after `getChildAt(1)` but it doesn't seem to affect the layout at all – Stelios Papamichail Sep 21 '19 at 11:29
  • @SteliosPapamichail So I would suggest to try to do a successful smoothscroll before trying to get the dimensions of the inner layout. Because now it's not clear if the problem is with the scroll or with getting the dimensions. – juancamilo87 Sep 21 '19 at 11:56
0

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

Sagar Gadani
  • 483
  • 5
  • 20
0

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.

Pavlo Ostasha
  • 8,161
  • 6
  • 23