Multiple pages at the same time on a ViewPager - android

Is there a possibility to display two pages at the same time, when using a ViewPager? I'm not looking for an edge effect, but rather for two full pages at the same time.

Please have a look at the getPageWidth Method in the corresponding PagerAdapter. Override it and return e.g. 0.8f to have all child pages span only 80% of the ViewPager's width.
More info:
http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getPageWidth(int)

See my more up-to-date answer here: Can ViewPager have multiple views in per page?
I discovered that a perhaps even simpler solution through specifying a negative margin for the ViewPager. I've created the MultiViewPager project on GitHub, which you may want to take a look at:
https://github.com/Pixplicity/MultiViewPager
Although this question specifically asks for a solution without edge effect, some answers here propose the workaround by CommonsWare, such as the suggestion by kaw.
There are various problems with touch handling and hardware acceleration with that particular solution. A simpler and more elegant solution, in my opinion, is to specify a negative margin for the ViewPager:
ViewPager.setPageMargin(
getResources().getDimensionPixelOffset(R.dimen.viewpager_margin));
I then specified this dimension in my dimens.xml:
<dimen name="viewpager_margin">-64dp</dimen>
To compensate for overlapping pages, each page's content view has the opposite margin:
android:layout_marginLeft="#dimen/viewpager_margin_fix"
android:layout_marginRight="#dimen/viewpager_margin_fix"
Again in dimens.xml:
<dimen name="viewpager_margin_fix">32dp</dimen>
(Note that the viewpager_margin_fix dimension is half that of the absolute viewpager_margin dimension.)
We implemented this in the Dutch newspaper app De Telegraaf Krant:

You have to override the getPageWidth() method on the viewpager's Adapter. For Example:
#Override
public float getPageWidth(int position) {
return 0.9f;
}
Try that code in your Adapter and then you'll understand.

See that blog entry.PagerContainer technique is solved my problem.
EDIT:
I found same answer.
How to migrate from Gallery to HorizontalScrollView & ViewPager?

You can solve this problem by using getPageWidth in PagerAdapter class.
Be sure about whether your JAR is up-to-date.Since previously ViewPager was not supporting multiple pages at the same time.
public float getPageWidth(){
return 0.4f;(You can choose it .For full screen per page you should give 1f)
}

create your layout file: my_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="#+id/pager_container"
android:layout_width="match_parent"
android:layout_height="240dp"
android:clipChildren="false">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="200dp"
android:clipToPadding="false"
android:layout_height="200dp"
android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_gravity="center" />
</FrameLayout>
</layout>
the viewpager is about as small as you want your pages to be. With android:clipToPadding="false" the pages outside the pager are visible as well. But now dragging outside the viewpager has no effect This can be remedied by picking touches from the pager-container and passing them on to the pager:
MyLayoutBinding binding = DataBindingUtil.<MyLayoutBinding>inflate(layoutInflater, R.layout.my_layout, parent, false)
binding.pager.setOffscreenPageLimit(3);
binding.pager.setPageMargin(15);
binding.pagerContainer.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return chatCollectionLayoutBinding.pager.onTouchEvent(event);
}
});

I don't think that's possible with the limitations of a View Pager. It only allows a user to view pages 1 at a time. You might be able to work something out with the use of fragments, and have 2 ViewPager fragments side by side and use buttons to work out the page flipping you want to implement, but the code may become very complex.
You can try something like a ViewFlipper - where you can do a lot more customizations (including animations).
Hope this helps.

It can be don in the Item Layout of the Viewpager. Assume that, you want two pages at a time.
This is the Item Layout (photo_slider_item.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" style="#style/photosSliderItem">
<ImageView android:id="#id/photoBox1" style="#style/photoBox"/>
<ImageView android:id="#id/photoBox2" style="#style/photoBox"/>
</LinearLayout>
And in your PagerAdapter:
#Override
public View instantiateItem(ViewGroup container, int position){
View sliderItem = LayoutInflater.from(container.getContext()).inflate(photo_slider_item, container, false);
ImageView photoBox1 = (ImageView) sliderItem.findViewById(R.id.photoBox1);
ImageView photoBox2 = (ImageView) sliderItem.findViewById(R.id.photoBox2);
photoBox1.setImageResource(photosIds[position]);
if(position < photosIds.length-1){
photoBox2.setImageResource(photosIds[position+1]);
} else {photoBox2.setImageResource(photosIds[0]);}
container.addView(sliderItem);
return sliderItem;
}
Edited version for more than two items
if you want more than two items, first add your items to the LinearLayout then use following algorithm:
photoBox1.setImageResource(photosIds[position]);
if(position < photosIds.length-i-1){
photoBox2.setImageResource(photosIds[position+1]);
photoBox3.setImageResource(photosIds[position+2]);
.
.
.
photoBox(i).setImageResource(photosIds[position+i-1]);
} else if(position < photosIds.length-i-2){
photoBox2.setImageResource(photosIds[position+1]);
photoBox3.setImageResource(photosIds[position+2]);
.
.
.
photoBox(i-1).setImageResource(photosIds[position+i-2]);
photoBox(i).setImageResource(photosIds[0]);
} . . . else if(position < photosIds.length-1){
photoBox2.setImageResource(photosIds[position+1]);
photoBox3.setImageResource(photosIds[0]);
photoBox4.setImageResource(photosIds[1]);
.
.
.
photoBox(i-1).setImageResource(photosIds[i-2-2]);
photoBox(i).setImageResource(photosIds[i-2-1]);
} else {
photoBox2.setImageResource(photosIds[0]);
photoBox3.setImageResource(photosIds[1]);
.
.
.
photoBox(i-1).setImageResource(photosIds[i-1-2]);
photoBox(i).setImageResource(photosIds[i-1-1]);
}
i : number of your items
[i-2-2] : number 2 in the middle is number of items in the last page of the viewpager.

Related

Android - Creating an Airbnb-like Horizontal Image Slider

I'm looking to replicate airbnb's app image slider where you have one image at the top of a view that you can horizontally swipe and it automatically goes to the next image upon swipe. I created a horizontalscrollview but it doesn't quite have the right functionality. It doesn't flip from image to image, upon swipe it sort of scrolls along the image and eventually to the next image. I've googled around quite a bit and haven't seen a non deprecated solution.
Any ideas?
EDIT - adding some of my code per request:
Basically at a high level I'm pulling in imageURLs from my AWS database (in a different class not shown below) and then trying to load those URLs into a horizontalscrollview using Picasso.
//generic instructions to allow insertion of pictures into a horizontalimageslider
public View insertPhoto(String path){
LinearLayout layout = new LinearLayout(getActivity());
layout.setGravity(Gravity.CENTER);
ImageView imageView = new ImageView(getActivity());
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
Picasso.with(getActivity() ).load(path).into(imageView); //tried this but got errors when running > resize(layout.getWidth(), layout.getHeight()), also tried .fit() after .load image wouldn't load
layout.addView(imageView);
return layout;
}
private class GetApartmentTask extends AsyncTask<ApiConnector,Long,Apartment >
//after a doInBackground
#Override
protected void onPostExecute(Apartment apartment) {
//to get image URL from database to then use with Picasso to download the image
mImageURLArraylist = mApartment.getApartmentImageArrayList();
for (int z = 0 ;z<mImageURLArraylist.size(); z++) {
mLinearLayout.addView(insertPhoto("http:" + mImageURLArraylist.get(z)) );
}
}}
in onCreateView method (alongside other things obviously)
mLinearLayout = (LinearLayout) v.findViewById(R.id.details_page_apartment_picture);
MyXML (relevant part)
<HorizontalScrollView
android:id="#+id/horizontal_scroll_view"
android:layout_width="match_parent"
android:layout_height="500dp"
android:fillViewport="true">
<LinearLayout
android:id="#+id/details_page_apartment_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
After many hours of frustration and some help getting over the finish line, the answer to swiping some part of the screen in this way is to use a viewpager.
Some great references:
swipe some part of the screen
http://developer.android.com/training/animation/screen-slide.html
What is the role of " isViewFromObject (View view, Object object)" in FragmentStatePagerAdapter?
my working code is provided in another question I posted that got me over the finish line :) --
Android ViewPager Won't Show Second Page?
I don't know the specifics of the airbnb app image slider, but it sounds like you could use flexslider. It's basically a JQuery toolkit. I have used it before in a website and it seems to have the functionality you are looking for.
https://www.woothemes.com/flexslider/

Android NestedScrollView has wrong size after app:layout_behavior

Since Google has published the design support library for android, there are many nice things that can be done without implementing custom code. While i've tested the custom views in this lib, i have found a worse thing, and i didn't know if this is a bug or not.
I have found the cheesesquare project on github. In the activity_detail.xml(layout file) there are 3 CardViews inside the NestedScrollView. If you delete 2 of them, you can see that the NestedScrollView doesn't have the full size of the parent(match_parent). The NestedScrollView is bound to the bottom of the parent view. http://i.stack.imgur.com/BXl7w.png
The NestedScrollView get's his full size when i remove the app:layout_behavior="#string/appbar_scrolling_view_behavior".
But when i remove the layout behavior, the toolbar is not collapsing.
Is there any fix for this? Example layout file can be found here: https://github.com/Smove/cheesesquare/blob/stackoverflow/app/src/main/res/layout/activity_detail.xml
You can build the cheesesquare apk from my github branch stackoverflow
I had this problem and fixed adding:
android:layout_gravity="fill_vertical"
to the NestedScrollView. Then it starts behaving correctly, as I explained here also. Of course the NestedScrollView needs some kind of child (i.e. it must not be empty), otherwise the toolbar won't collapse.
Update
While this works well with small content, I noticed it has some problems showing longer contents, e.g. like the full activity_detail.xml above. The problem is that you can't scroll to the very bottom part of the content - it is unreachable at the bottom.
From my tests I could find that the missing part is as big as the collapsed toolbar (or at least that's what it looks to me). To fix this is issue, and having a solution reliable for both small and big contents, you should add a layout_marginBottom to the ScrollView, so that it gets measured and releases the missing bottom part. Thus:
android:layout_gravity="fill_vertical"
android:layout_marginBottom="?attr/actionBarSize"
or whatever size you gave to the Toolbar.
But still
Scrolling with small contents with this solution, even if the content is justly aligned at the top, isn't really smooth as scrolling with large contents. I'll use until a library fix comes.
Update2
Looks like this was fixed in v22.2.1 .
using the answer by #natario If you instead set a padding for the child (LinearLayout in my case) it will look better:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_gravity="fill_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="?attr/actionBarSize">
<!--Rest of the code-->
Or in Kotlin you can do something like this:
coordinator.doOnLayout {
nestedScrollView.minimumHeight = resources.displayMetrics.heightPixels - with(TypedValue().also {theme.resolveAttribute(android.R.attr.actionBarSize, it, true)}) {
TypedValue.complexToDimensionPixelSize(data, resources.displayMetrics)}
}
add android:minHeight="?attr/actionBarSize" to CollapsingToolbarLayout
Workaround
Before showing my NestedScrollView and after binding the data to the NestedScrollView content, I call the method fullScroll(int direction) of my NestedScrollView instance with the View.FOCUS_UP direction as argument.
Code example for a fragment:
NestedScrollView scrollView = (NestedScrollView) getActivity().findViewById(R.id.scroll_view);
scrollView.fullScroll(View.FOCUS_UP);
use RecyclerView replace NestedScrollView fix this bug
set item count 1,that ViewHolder return your real contentView;
my code:
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
// 添加分割线
recyclerView.addItemDecoration(new DividerItemDecoration(getApplicationContext()));
recyclerView.setAdapter(new Adapter<ViewHolder>() {
#Override
public int getItemCount() {
return 1;
}
#Override
public void onBindViewHolder(ViewHolder holder, int arg1) {
WebView view = (WebView) holder.itemView;
view.getSettings().setJavaScriptEnabled(true);
view.loadUrl("http://www.baidu.com");
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup arg0, int arg1) {
return new ViewHolder(inflater.inflate(R.layout.webview, arg0, false)) {
};
}
});

Seamless nested scrolling (Android)

We've all been advised against nesting views that contain a scrolling mechanism. However, in the latest Android release (5.0), the Phone app caught my attention with what seems to be a ListView inside of a ScrollView.
What really intrigued me was that the scrolling mechanism switched from the ScrollView to the ListView seamlessly.
Notice the content above the tabs is pushed out of view before the actual ListView begins scrolling.
I've tried duplicating this myself, but ended up unsuccessful. Here is the basic approach I was taking...
With a single, continuous touch event (no lifting of the finger) ...
As user scrolls, the ListView slowly covers up the ImageView. Once the ImageView is 100% covered and the ListView takes up the entire screen, the ListView begins to scroll.
I'm currently listening to touch events on the ListView and if the top has been reached, call requestDisallowInterceptTouchEvent on the ListView, i.e.
#Override
public boolean onTouch(View v, MotionEvent event) {
if (listViewAtTop) {
v.requestDisallowInterceptTouchEvent(true);
} else {
v.requestDisallowInterceptTouchEvent(false);
}
return false;
}
The switching scrolling context works, only if you lift your finger and continue scrolling.
Is there a different approach that will achieve the desired effect?
Android 5.0 Lollipop (API 21) added nested scrolling support.
From what I can tell, both ListView (AbsListView) and ScrollView support this now (if running on API 21), but it must be enabled on the scrolling views.
There are two ways, by calling
setNestedScrollingEnabled(true) or with the layout attribute android:nestedScrollingEnabled="true" (which is undocumented)
To learn about how it works, or to support this for a custom widget, the key methods are these:
onStartNestedScroll
onNestedScrollAccepted
onNestedPreScroll
onNestedScroll
onStopNestedScroll
Unfortunately, there is no guide or training which explains how this works other than the JavaDoc itself which is rather light and there are no examples other than ScrollView.
Add latest support package 'com.android.support:support-v4:22.1.1' to your project. And try this:
<android.support.v4.widget.NestedScrollView
android:id="#+id/nScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<FrameLayout ...>
<ListView ... />
</FrameLayout >
</android.support.v4.widget.NestedScrollView>
By default nested scrolling is Enabled.
While trying to figure out how to solve this issue myself, I found this question first; however, the answer didn't really go into too much detail. I did find a lot of good resources, so if anyone else finds themselves looking for this, I'll link them below. A term for this effect is "Sticky Scrolling".
An article talking about "Synchronized Scrolling".
http://www.pushing-pixels.org/2011/07/18/android-tips-and-tricks-synchronized-scrolling.html
A good video showcasing some Android scrolling tricks, "Quick Return" and "Sticky Scrolling".
https://www.youtube.com/watch?v=PL9s0IJ9oiI
Code:
https://code.google.com/p/romannurik-code/source/browse/misc/scrolltricks
And lastly, here is another one showcasing the same effect using a listView instead of a ScrollView.
https://www.youtube.com/watch?v=rk-tLisxSgM
Code:
https://github.com/jatago/list_sticky_scroll_trick
I found an alternative 'trick' which is quite simple... Use only a ListView with an added transparent header.
I have been wanting to achieve the same effect as well. I came up finding a relevant library called ObservableScrollView in GitHub and it requires more work on the back-end via a TouchInterceptFramework but at least it did the job even for pre-lollipop devices. It also supports not only child scrollviews and listviews but also recyclerviews. Here's the link:
https://github.com/ksoichiro/Android-ObservableScrollView
I hope they consider nested scrolling for both lollipop and pre-lollipop devices as a part of their design standard soon. This is a good sign.
This is classic example of dummy layouts. Something not entirely obvious at first look. Basically the scenario is something like this.
Grey Area->FrameLayout
Followed by a listview that fills up the entire framelayout and followed by a imageview that overlaps the top half of a listview. The listview's first item is a dummy item and has a height identical to that of the imageview.
(Note: The actual data starts from the second element)
Next Step is easy
Translate the Imageview as per the scroll of the listview.
I suppose this is the best way to do that whilst avoiding nested scrolling
You can use the following combination of attributes on your ListView to achieve this:
<ImageView ... /> <!-- must be before ListView -->
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="..." <!-- height of imageView -->
android:clipToPadding="false"
...
/>
You don't have to manage any scrolling in your code at all, and it requires no header/dummy views in your list adapter.
I am using something like this and it works ok I think
scrollView.onScroll { x, y ->
Timber.d("ScrollView offset: ($x, $y)")
val height = dashboardChart.measuredHeight
val recyclerView = viewPager.findViewById<RecyclerView>(R.id.recyclerView)
if(y >= height) {
Timber.d("ScrollView enable nested scrolling!")
recyclerView.isNestedScrollingEnabled = true
} else {
Timber.d("ScrollView disable nested scrolling!")
recyclerView.isNestedScrollingEnabled = false
}
}
Where scrollView is parent I am listening onScroll event (it is extension underneath it is viewTreeObserver.addOnScrollListener). Then depending whether I've scrolled initial offset or not I am enabling/disabling child recyclerView (similary ListView or other scrollView) scrolling.

Set height of children in RecyclerView?

I am trying to use RecyclerView in a similar way to ViewPager (Vertical).
I have setup fling and scroll gestures so the views are scrolled in exactly the same way as ViewPager but now I would like to setup children views (LinearLayoutManager) and LinearLayout used for each child view to fill screen instead of wrap_content. I have made all views to match_parent and fill_parent but that does not work.
I did this:
holder.layout.setMinimumHeight(this.recyclerView.getMeasuredHeight());
Which is nice but when the orientation changes then layout overflows the screen which makes smooth scrolling/gestures flicker etc. I don't want it to overflow the screen.
Any good tips how to make it properly so all children are laid out to maximum height of the screen but do not overflow?
Thanks
Edit: I changed setting minimum height to this:
holder.layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, this.recyclerView.getHeight()));
which solves flickering issue but is there a better way?
I have low reputation so unable to comment down. thats why answering here .
to over come the overflow issue lets say you have XMl of single item like this
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:id="#+id/mainLayout" >
<-- some views --->>
</RelativeLayout>
now in your adapter get this Layout in viewHolder
and make a boolean variable where you are setting adabpter.. which you can use for knowing orientation changed . when orientation get changed then change its value .
in your adapter make a function
public void orientaiotnChange(){
notifyDataSetChanged();
}
in your function
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int arg1) {
if(isOrientationHorizontal){
viewHolder.Mainlayout.setOrientation(horizontal);
}
else{
viewHolder.Mainlayout.setOrientation(vertical);
}
also change the orientation of RecyclerView in activity from where you set adapter and from where you are checking orientation is changed or not .
hopefully it will work so :)

Parallax Effect in Android's ViewPager

I'm trying to emulate a parallax effect when sliding through my fragments, I've read about beginFakeDrag and fakeDragBy but to be honest, I don't know even if it's the best approach to my problem.
Anyone has done something similar with the ViewPager or have a hint about how should I approach this?
Thank you
An easy way to do this without using a custom library is to implement ViewPager.PageTransformer
I created my layouts to use the same id for their background element. For my example all background images will use the id background
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/background"
android:src="#drawable/img12"
android:scaleType="fitXY"/>
Then when I go in to implement ViewPager.PageTransformer I can reference that image like so:
public class Transformer implements ViewPager.PageTransformer{
#Override
public void transformPage(View page, float position) {
if(position >= -1 && position <= 1){
page.findViewById(R.id.background).setTranslationX(-position * page.getWidth() / 2);
} else {
page.setAlpha(1);
}
}
}
Finally, I assign my ViewPager.PageTransformer to my ViewPager like so.
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setPageTransformer(false, new Transformer());
This question is a bit old, but I found it when I was trying to do exactly that...
I implemented my own solution, basically extending ViewPager and overriding onDraw.
You can find all the code with a simple example here
I know that it's a bit old but take a look to that https://github.com/xgc1986/ParallaxPagerLibrary
It not overrides the onDraw method, and the effect not only with images, it works with every kind of view
mPager.setPageTransformer(false, new ParallaxTransformer(R.id.parallaxContent));
R.id.paraallaxContent is the id of the View you want to have this effect
unless the other solutions, don't need any any concrete structure to work, and also is layout independant
demo: youtube
Maybe this library can help you:
https://github.com/garrapeta/ParallaxViewPager
You can take a look at this :
https://github.com/luxsypher/ParallaxViewPager
you can apply a parallax effect on any element of your view and gave them all different speed
This is a ViewPager subclass I wrote, pretty easy to use. You don't need to do anything different with it, just include the dependency and use it as a standard ViewPager. Available on GitHub.
This library is fully customizable in x and y directions and includes alpha effects:
https://github.com/prolificinteractive/ParallaxPager
Installation (as of v0.7, check README for updates):
Add as a Maven Central dependency with Gradle
Use a ParallaxContainer in layout XML instead of ViewPager
Create a layout XML file for each page (the x/y/alpha attributes can be set separately for each object moving in/out of the page)
There are a few copy/paste lines to add to onCreate of your Activity
Maybe this library could be useful:
https://github.com/matrixxun/ProductTour
?
it uses "ViewPager.PageTransformer" for making things move differently inside.

Categories

Resources