Reputation: 1270
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:
Upvotes: 4
Views: 2681
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
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
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
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
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):
<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
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center">
Upvotes: 1