Hi i am showing vertical list using recycler view and i am using a gradient background for recycler view.I am deleting items in recycler view when they are swiped left or right using ItemTouchHelper.
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mRecyclerAdapter.removeStock(viewHolder.getAdapterPosition());
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if(actionState!=ItemTouchHelper.ACTION_STATE_IDLE){
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
}
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
Here i am changing recycler view item background to light grey when item is swiped but i want the original background back when recycler view item goes back to idle state i.e i want that gradient background back.
Recylerview xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gradient_background"
tools:context=".ui.StockFragment"
tools:showIn="#layout/activity_main">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="none"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
Drawable file:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:type="linear"
android:startColor="#FF18181F"
android:endColor="#FF27354D"
android:angle="90"/>
</shape>
Perhaps you can try inside of onSelectedChanged(). Alternatively, perhaps you can override clearView() and do the change there after calling the superclass method.
EDIT
Having read the documentation more, I now think onSelectedChanged() is the correct place to change the background both for when the item starts swiping and when it returns to idle. Check that the viewHolder is not null and then check the actionState for what to change the background to.
I think onChildDraw() is not the right place to do this because it is already in the drawing phase and changing the view's background there will probably cause another re-draw.
Related
I have a layout where i have a bottom sheet which could be expanded, then from that bottomsheet i can click some items which then will be added to my RecyclerView, the issue is that when the bottomsheet is expanded i'm unable to see the last added items as the recyclerView goes behind the bottomSheet.
So i would do something like the bottomSheet pushes to top the recyclerView (or that the recyclerView is resized)
The issue is that i was trying to do the resize in onSlide but it doesn't work as expected...
Here is my Layout:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
app:layout_anchorGravity="top"
android:layout_marginBottom="60dp"
app:layout_anchor="#+id/bottomSheet"
android:padding="2dp"
android:scrollbars="vertical"
tools:listitem="#layout/recyclerview_pterm" />
<include layout="#layout/bottom_sheet_pterm" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And my BottomSheetBehavior callback:
bottomSheet.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
mRecyclerViewTOP.scrollToPosition(dummyDataItems.size() - 1);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
int padding = bottomSheet.getHeight();
ViewGroup.LayoutParams params= mRecyclerViewTOP.getLayoutParams();
params.height = params.height - padding;
mRecyclerViewTOP.setLayoutParams(params);
}
});
So how could i make the recyclerView shows ever the last inserted item even when bottomSheet is expanded?
I wanted to show the part of next and previous items of the recyclerview as compared to the currently visible item (as in this third party library). However I managed to do so with my native recyclerview.
That's sound great to me, now I want to set the height of my currently visible item larger than the next and previous items to it as shown in the gif of the above mentioned library!
I have managed to show the next and previous items with my code as in the following stages:
1. Setting the recyclerview adapter as:
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
locationTypeFragmentBinding.mRecylerview.setLayoutManager(layoutManager);
locationTypeFragmentBinding.mRecylerview.setHasFixedSize(true);
final LocationTypePictureAdapter locationTypePictureAdapter =
new LocationTypePictureAdapter(getActivity(), locationDetails,false);
final SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(locationTypeFragmentBinding.mRecylerview);
locationTypeFragmentBinding.mRecylerview.post(new Runnable() {
#Override
public void run() {
locationTypeFragmentBinding.mRecylerview.
setAdapter(locationTypePictureAdapter);
}
});
2. My RecyclerView in the xml is:
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecylerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/buttonsHolder"
android:clipToPadding="false"
android:orientation="horizontal"
android:padding="#dimen/_10sdp"
android:paddingStart="#dimen/_15sdp"
android:paddingEnd="#dimen/_15sdp"
android:scrollbarStyle="outsideOverlay"
android:visibility="gone"/>
3. My RecyclerView item xml is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="#dimen/_200sdp">
<android.support.v7.widget.CardView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_5sdp"
android:layout_marginEnd="#dimen/_5sdp"
android:background="#android:color/transparent"
app:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/locationPicture"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
4. What I need to achieve is like:
I know I can use the above mentioned library, but I want to set the height of the currently visible item larger than the next and previous items of my recyclerview which are to be shown to the user.
Can somebody please figure out what I am doing wrong with my code?
Example Image of what I need
See Here
I am not familiar the library that you are using but You can also use CarouselLayoutManager to achieve this look, with this library you will have one elevated item that will be above all others and this will look bigger than the rest of the items.
How to use:
In your gradle:
implementation 'com.azoft.carousellayoutmanager:carousel:version'
When declaring an adapter:
final CarouselLayoutManager layoutManager = new CarouselLayoutManager(CarouselLayoutManager.VERTICAL);
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
Edit:
If you want to do it natively you can do something like this:
Create recyclerView:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadingEdge="horizontal"
android:overScrollMode="never"
android:requiresFadingEdge="horizontal" />
Attach your recyclerView to SnapHelper like this:
LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
Now you need to provide the logic for your currently centered item:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
float position = (float) recyclerView.computeHorizontalScrollOffset() / (float) itemHeight;
int itemPosition = (int) Math.floor(position);
}
super.onScrollStateChanged(recyclerView, newState);
}
});
I had added animation to items of a recycleView using the below method. I hope it may solve your problem if you are able to do something similar to this
Try this changes in your onBindViewHolder of your recycleView adapter.
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position)
{
// do your work
setAnimation(holder.itemView, position);
}
and in setAnimation which receives the view and its position
void setAnimation(View view, int position) {
//this allows new views coming in the recycle view to slide to left while scrolling down and slide to right while scrolling up.
if (lastPosition < position) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
view.startAnimation(animation);
} else {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_in_right);
view.startAnimation(animation);
}
lastPosition = position;
}
Similarly, if you know the position or location of view which is in middle, you can use your anim to zoom it up or zoom down other views in the recycleView.
If you cary about performance it is the best to do all animations things in Layout Manager. Tamir Abutbul gives you very good solution, why you want to reinvent the wheel? Without library there is ready layout manager you need : https://stackoverflow.com/a/41307581/2551094
How to hide/show view when scrolling up/down android like Foodpanda app
I want to hide/show view (linear or relative layout) when ScrollView is up/down like this above gif.
But my app I do not use Recyclerview or list view (just textview).
How can I create it?
Thanks!
Add scroll listener to the RecylerView
If the user is scrolling down - then start translation animation UPWARDS
If the user is scrolling up - then start translation animation DOWNWARDS
Anim translation UPWARDS:- (trans_upwards.xml)
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromYDelta="0%p"
android:toYDelta="100%p"
android:duration="300"
/>
</set>
Anim translation DOWNWARDS:-(trans_downwards.xml)
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromYDelta="100%p"
android:toYDelta="0%p"
android:duration="300"
/>
</set>
Add scroll listener to recyclerView (and also do a checking)
boolean check_ScrollingUp = false;
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
// Scrolling up
if(check_ScrollingUp)
{
YourView.startAnimation(AnimationUtils.loadAnimation(context,R.anim.trans_downwards));
check_ScrollingUp = false;
}
} else {
// User scrolls down
if(!check_ScrollingUp )
{
YourView
.startAnimation(AnimationUtils
.loadAnimation(context,R.anim.trans_upwards));
check_ScrollingUp = true;
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
I'm developing on Amazon Fire TV.
Because it's a TV app(No touch), I need focusables inside row's layout to be able to navigate around.
I have a really simple Recyclerview with image, text, and a focusable. When I press up or down, it all scrolls and stuff correctly, but I noticed that when I navigate faster than scroll can keep up, it creates new viewholders (Off screen) and lags up the UI.
I have created an activity with Creation numbers on it. When I scroll slowly, the highest creation # is 10. But when I scroll fast, I get cards with creation number 60 in a second. This causes an enormous lag and the application drops a lot of frames. Is my approach totally wrong?
Use the code below to test this out.
/**
* Created by sylversphere on 15-04-15.
*/
public class LandfillActivity extends Activity{
private Context context;
private static int ticketNumber;
private static int getTicket(){
ticketNumber ++;
return ticketNumber;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
setContentView(R.layout.landfill_activity);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
GridLayoutManager glm = new GridLayoutManager(context, 2);
recyclerView.setLayoutManager(glm);
SickAdapter sickAdapter = new SickAdapter();
recyclerView.setAdapter(sickAdapter);
}
public class SickViewHolder extends RecyclerView.ViewHolder{
TextView ticketDisplayer;
public ImageView imageView;
public SickViewHolder(View itemView) {
super(itemView);
ticketDisplayer = (TextView) itemView.findViewById(R.id.ticketDisplayer);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
itemView.findViewById(R.id.focus_glass).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
context.startActivity(new Intent(context, LouisVuittonActivity.class));
}
});
}
public void setTicket(int value){
ticketDisplayer.setText(""+value);
}
}
public class SickAdapter extends RecyclerView.Adapter<SickViewHolder>{
#Override
public SickViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
SickViewHolder svh = new SickViewHolder(getLayoutInflater().inflate(R.layout.one_row_element, null));
svh.setTicket(getTicket());
return svh;
}
#Override
public void onBindViewHolder(SickViewHolder holder, int position) {
String[] image_url_array = getResources().getStringArray(R.array.test_image_urls);
Picasso.with(context).load(image_url_array[position % image_url_array.length] ).fit().centerCrop().into(holder.imageView);
}
#Override
public int getItemCount() {
return 100000;
}
}
}
one_row_element.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#mipmap/sick_view_row_bg" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical"
android:layout_marginLeft="15dp"
android:orientation="horizontal">
<TextView
android:id="#+id/virusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Creation #"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="#+id/ticketDisplayer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textColor="#fff"
android:textSize="40sp" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/focus_glass"
android:background="#drawable/subtle_focus_glass"
android:focusable="true"
android:focusableInTouchMode="true"/>
</FrameLayout>
</FrameLayout>
test_image_urls.xml (Urls not owned by me)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="test_image_urls"
formatted="false">
<item>http://farm4.static.flickr.com/3175/2737866473_7958dc8760.jpg</item>
<item>http://farm4.static.flickr.com/3276/2875184020_9944005d0d.jpg</item>
<item>http://farm3.static.flickr.com/2531/4094333885_e8462a8338.jpg</item>
<item>http://farm4.static.flickr.com/3289/2809605169_8efe2b8f27.jpg</item>
<item>http://2.bp.blogspot.com/_SrRTF97Kbfo/SUqT9y-qTVI/AAAAAAAABmg/saRXhruwS6M/s400/bARADEI.jpg</item>
<item>http://fortunaweb.com.ar/wp-content/uploads/2009/10/Caroline-Atkinson-FMI.jpg</item>
<item>http://farm4.static.flickr.com/3488/4051378654_238ca94313.jpg</item>
<item>http://farm4.static.flickr.com/3368/3198142470_6eb0be5f32.jpg</item>
<item>http://www.powercai.net/Photo/UploadPhotos/200503/20050307172201492.jpg</item>
<item>http://www.web07.cn/uploads/Photo/c101122/12Z3Y54RZ-22027.jpg</item>
<item>http://www.mitravel.com.tw/html/asia/2011/Palau-4/index_clip_image002_0000.jpg</item>
<item>http://news.xinhuanet.com/mil/2007-05/19/xinsrc_36205041914150623191153.jpg</item>
<item>http://ib.berkeley.edu/labs/koehl/images/hannah.jpg</item>
<item>http://down.tutu001.com/d/file/20110307/ef7937c2b70bfc2da539eea9df_560.jpg</item>
<item>http://farm3.static.flickr.com/2278/2300491905_5272f77e56.jpg</item>
<item>http://www.pic35.com/uploads/allimg/100526/1-100526224U1.jpg</item>
<item>http://img.99118.com/Big2/1024768/20101211/1700013.jpg</item>
<item>http://farm1.static.flickr.com/45/139488995_bd06578562.jpg</item>
</string-array>
</resources>
subtle_focus
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="#color/glass_focus"/>
<item android:drawable="#color/glass_normal"/>
</selector>
glass_normal is #9000
glass_focus is #0000
Try increasing the maximum number of recycled views in the pool:
recyclerView.getRecycledViewPool().setMaxRecycledViews(50);
50 is an arbitrary number, you can try higher or lower and see what happens.
RecyclerView tries to avoid re-using views that have transient state, so if views are invalidated quickly or are animating, they may not be re-used right away.
Similarly if you have many smaller views, you may end up with more on screen than the default pool size can handle (more common with grid like layouts).
Picasso is holding you up but the suggested solution to build your own mechanism is not the way to go.
Picasso has fallen behind in the last year or so and today there are far better alternatives in the form of Google Glide and Facebook Fresco which specifically released updates to work better with RecyclerView and have proved faster and more efficient in loading, caching and storing in many tests which are available online such as:
http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/
I hope that helped.
Good luck.
As the commenters pointed out pending responses from Picasso might be holding you up. If that is the case, you can solve it by extending ImageView and overriding the following method. I think it is worth trying.
#Override
protected void onDetachedFromWindow() {
Picasso.with(context).cancelRequest(this);
super.onDetachedFromWindow();
}
Update:
Turns out this is not the correct way, anyone wanting to cancel requests should do so in the onViewRecycled() callback as pointed out in the comments below.
By digging deeper in Sam Judd's answer I forced recycler to recycle the views by implementing the followings in its adapter.
#Override
public boolean onFailedToRecycleView(#NonNull VH holder)
return true;
}
As you can see here:
Called by the RecyclerView if a ViewHolder created by this Adapter cannot be recycled due to its transient state. Upon receiving this callback, Adapter can clear the animation(s) that effect the View's transient state and return true so that the View can be recycled. Keep in mind that the View in question is already removed from the RecyclerView.
In some cases, it is acceptable to recycle a View although it has transient state. Most of the time, this is a case where the transient state will be cleared in onBindViewHolder(ViewHolder, int) call when View is rebound to a new position. For this reason, RecyclerView leaves the decision to the Adapter and uses the return value of this method to decide whether the View should be recycled or not.
Note that when all animations are created by RecyclerView.ItemAnimator, you should never receive this callback because RecyclerView keeps those Views as children until their animations are complete. This callback is useful when children of the item views create animations which may not be easy to implement using an RecyclerView.ItemAnimator.
You should never fix this issue by calling holder.itemView.setHasTransientState(false); unless you've previously called holder.itemView.setHasTransientState(true);. Each View.setHasTransientState(true) call must be matched by a View.setHasTransientState(false) call, otherwise, the state of the View may become inconsistent. You should always prefer to end or cancel animations that are triggering the transient state instead of handling it manually.
For anyone else looking for a quick hack,
Do this. This will delay selection until it's been inflated and selected.
I don't know how but it works.
Just return null on onFocusSearchFailed.
/**
* Created by sylversphere on 15-04-22.
*/
public class SomeGridLayoutManager extends GridLayoutManager{
private final Context context;
public SomeGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
this.context = context;
}
public SomeGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
this.context = context;
}
#Override
public View onFocusSearchFailed(View focused, int focusDirection, RecyclerView.Recycler recycler, RecyclerView.State state) {
return null;
}
}
I have a ViewPager implemented without fragment (just view). Each page contains a list of elements, but the list hasn't always the same size.
I tried to set the ViewPager dimension with this code (extends ViewPager so I can override this function) :
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for(int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if(h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
The problem is that it set the same height for every page. I need a custom height for each page, depending of the height of the list.
I also tried to use setOnPageChangeListener calling requestLayout() and invalidate() on the ViewPager, but the size remains the same. Maybe I did it wrong...
Here is some code that might be useful :
A part of my PagerAdapter:
#Override
public Object instantiateItem(ViewGroup container, int position) {
// Inflate a new layout from our resources
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_home_pager,
container, false);
mContainerView = (ViewGroup) view.findViewById(R.id.news_container);
reloadNews(position);
// Add the newly created View to the ViewPager
container.addView(view);
// Return the View
return view;
}
A part of my XML layout:
<ScrollView
android:id="#+id/news_scrollview"
android:layout_width="match_parent"
android:layout_height="fill_parent">
<com.ViewPagerWithHeight
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</ScrollView>
Thanks of lot for helping me,
The ViewPager height cannot vary per-page as you are hoping. You could attempt to subclass ViewPager to add this ability, but handling the visual transitions between differently-sized pages is going to be very fiddly. Another alternative may be to re-measure the ViewPager on every page change (but I would expect the transition to look pretty bad). You would need to set a page change listener, then call requestLayout on the ViewPager. Your ViewPager onMeasure would need to find the height of the currently-visible child only, and set the ViewPager height to match this.
Aside: I don't see you calling setMeasuredDimension anywhere. When measuring a view, you must call this method with your calculated width and height to inform the view what size it has been measured at. Currently you are calling through to super.onMeasure at the end of your custom onMeasure which, while valid, means the ViewPager will always be measured with the "default" width and height. In this case, that happens to match the height of the largest page anyway.
See the docs for onMeasure for more details. In particular:
CONTRACT: When overriding this method, you must call setMeasuredDimension(int, int) to store the measured width and height of this view. Failure to do so will trigger an IllegalStateException, thrown by measure(int, int). Calling the superclass' onMeasure(int, int) is a valid use.
I just find out something that do the job.
I moved the Scrollview inside the pageItem.xml so I can set the page size (for all pages) but still can scroll if the list is long enough. The ViewPager is now inside a FrameLayout with layout_height = fill_parent.
The page size is fixed, but the scrollview do the trick...
The ViewPager (inside my fragment) :
<FrameLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/viewpagercontainer">
<com.ViewPagerWithHeight
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</FrameLayout>
The "Page item" :
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/news_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:showDividers="middle"
android:divider="?android:dividerHorizontal" />
</ScrollView>
onMeasure function:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(containerHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
How to set the attribute containerHeight (more info here):
final View pagerContainer = (View) mView.findViewById(R.id.viewpagercontainer);
pagerContainer.post(new Runnable() {
#Override
public void run() {
mViewPager.setContainerHeight(pagerContainer.getMeasuredHeight());
}
});