I'm using VerticalViewPager for swiping vertically through images. The vertical view pager is strict when it comes to swiping angle, which means it will proceed with swiping only if it is a perfectly vertical swipe (no change in x coordinate).
But I have observed in the Inshorts app (Inshorts), they allow swiping up even if the swipe is not perfectly vertical. This makes the swiping smoother as users might not always be doing a 100% perfect swipe.
How can we achieve this?
You can use ViewPager.PageTransformer.
A PageTransformer is invoked whenever a visible/attached page is
scrolled. This offers an opportunity for the application to apply a
custom transformation to the page views using animation properties.
private class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // [0,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
You can use VerticalViewPager
Related
How do i detect if i have clicked or press at right side of viewPager or at left side of viewPager.
I have tried with GestureDetector but couldn't make it out.
Help me
Use the GestureDetector to get SingleTapConfirmed Action
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
float x=e.getX()
if(x < ( getWidth() * 0.5 )){
//also check if item we set if valid or not i.e (getCurrentItem() - 1) > 0
setCurrentItem( getCurrentItem() - 1)
}else{
//also check if item we set if valid or not i.e (getCurrentItem() + 1) < maxChildCount
setCurrentItem( getCurrentItem() + 1)
}
return true;
}
add this code in your custom ViewPager
I'm writing a html page reader, cant load all .html because its huge and performance is bad, so I decided to split it into 3(or more) html and load that inside Web View nested with View Pager (swipe vertically)
My problem is that I should swipe slowly to scroll the web view and swipe fast to change view pager
Slow swiping
fast swipe change the Page on ViewPager
1) Can i expand webview to all its content heigh inside viewpager ?
2) Can change viewpager item only when topScroll or endScroll?
what i've tried so far:
CustomWebView
#Override
public boolean onTouchEvent(MotionEvent event) {
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
worked but was unable to change viewpager item
so i though about enable/disable it when i get to the top or to the end
removed webview onTouchEvent and added:
#Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
requestDisallowInterceptTouchEvent(true);
int height = (int) Math.floor(this.getContentHeight() * this.getScale());
int webViewHeight = this.getMeasuredHeight();
boolean scrollTop = this.getTop() == t;
boolean scrollEnd = this.getScrollY() + webViewHeight >= height;
if(scrollTop || scrollEnd) {
requestDisallowInterceptTouchEvent(false);
}
worked randomly, the most common thing is that when i change page, i must scroll down and scroll up to trigger the requestDisallow to false so i can change page =[
Vertical CustomViewPage is this one ->
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
1st i think it's a bad idea to split your content into 3 different HTML files and putting them on 3 different WebViews.
3 fils can be a good idea but 3 WebView in 3 Views of ViewPager is a bad idea.
Instead, you should detect top and bottom of the webpage using ".js" / "jQuery" and route page/HTML within same WebView.
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
// you're at the bottom of the page
}};
There are many ways to detect TOP and BOTTOM of your HTML content.
Still, if you want to increase the height of your review to content height use
Getting WebView Content height once its loaded Android it worked for me.
I am designing tab view like feature, but i need one more functionality.
Suppose i have three tabs,
And if press tab2 - Content of second tab will show
tab3 -- Content of Third will show
tab1 - content of tab1 will show
and by default tab1 will be selected. and this is working fine.
Now, i need when i am scrooling the content of tab1, i need to show cotent of second tab too ( But second tab should be selected).. Just like single page application on web..
I don't need Web view. Anybody guide me how to achieve this, or if there is any sample code available on github. Please
Thanks
#AnkitaKashyap sorry mate, I kept forgot, here is your snippet code (in kotlin) if you need help, pls send me a private msg,if i got your idea correctly, here is what you want gif demo:
using a tabbar with recyclerview and set addOnTabSelectedListener:
productTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
productRv.scrollToPosition(tab?.position?:0)
}
})
and set in your recyclerview :
productRv.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
var scrollPosition = layoutManager.findFirstVisibleItemPosition()
productTabs.getTabAt(scrollPosition)?.select()
}
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
})
You need to go with VerticalViewPager as shown in this StackOverflow post and use TabLayout along with it.
Code from the given SO link:
/**
* Uses a combination of a PageTransformer and swapping X & Y coordinates
* of touch events to create the illusion of a vertically scrolling ViewPager.
*
* Requires API 11+
*
*/
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
I am building an android application similar to inshorts. I wanna to slide my cardView up and down. What I am doing yet - I am parsing the data from server using webAPI then using BaseAdapter displaying in cardView. But now I need on swipe up it should move up and next position card should be displayed .
You can do this with ViewPager and Fragments then you need to put slide animation with view pager. For horizontal slide you can see developers reference http://developer.android.com/training/animation/screen-slide.html.
After that you need to modify view pager slightly so that it behave like vertical instead of horizontal and you can achieve this with below code:
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // [0,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
One way you can do this is by using fragments and ViewPager to load the pages, and you can specify Property Animation to animate the fragments.
If you are new to fragments, try beginning from here
And then you need ViewPager to swipe between pages. here
Property Animation is often used to animate native fragments(Android.App.Fragment) . see this
and see this to swap fragments using Animation
I am putting a Custom WebView inside of a Custom ViewPager:
https://github.com/JakeWharton/Android-DirectionalViewPager
I've set the ViewPager to page in the vertical direction, which is the same direction my WebView scrolls, how ever the ViewPager intercepts all touch events.
So how it should work is that the WebView scrolls till it reaches the end, then once it is at the end of its scroll, the ViewPager should be allowed to page to the next page.
I guess, in the ViewPager, I need to find out, when a touch event occurs, the list of child Views that could potentially respond to the event, see if they are scrollable and respond appropriately.
How can I find out this list of potential child views that would receive the touch event if the ViewPager ignored the touch event?
Take a cue from how Android does their ViewPager.
/**
* Tests scrollability within child views of v given a delta of dx.
*
* #param v View to test for horizontal scrollability
* #param checkV Whether the view v passed should itself be checked for scrollability (true),
* or just its children (false).
* #param dx Delta scrolled in pixels
* #param x X coordinate of the active touch point
* #param y Y coordinate of the active touch point
* #return true if child views of v can be scrolled by delta of dx.
*/
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int scrollX = v.getScrollX();
final int scrollY = v.getScrollY();
final int count = group.getChildCount();
// Count backwards - let topmost views consume scroll distance first.
for (int i = count - 1; i >= 0; i--) {
// TODO: Add versioned support here for transformed views.
// This will not work for transformed views in Honeycomb+
final View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
canScroll(child, true, dx, x + scrollX - child.getLeft(),
y + scrollY - child.getTop())) {
return true;
}
}
}
return checkV && ViewCompat.canScrollHorizontally(v, -dx);
}
It literally goes through the entire view hierarchy and does a hit test to see if the touch lies within the view bounds, and if so, check if that view can scroll.