_From @alexrainman on October 28, 2016 13:35_
I have this custom ViewPager that overrides touch gestures to support vertical swipe:
export class VerticalViewPager extends android.support.v4.view.ViewPager
{
constructor(context: android.content.Context, attrs?: android.util.IAttributeSet){
super(context, attrs);
//this.setPageTransformer(false, new DefaultTransformer());
return global.__native(this);
}
private swapTouchEvent(ev: android.view.MotionEvent)
{
var width = this.getWidth();
var height = this.getHeight();
var swappedX = (ev.getY() / height) * width;
var swappedY = (ev.getX() / width) * height;
ev.setLocation(swappedX, swappedY);
return ev;
}
public onInterceptTouchEvent(ev: android.view.MotionEvent)
{
var intercept = super.onInterceptTouchEvent(this.swapTouchEvent(ev));
//If not intercept, touch event should not be swapped.
this.swapTouchEvent(ev);
return intercept;
}
public onTouchEvent(ev: android.view.MotionEvent)
{
return super.onTouchEvent(this.swapTouchEvent(ev));
}
}
This works fine but i have to apply a page transformer to enable vertical scrolling, that's the part that doesn't works.
Normally i implement the PageTransformer like this (and this works in well in Java):
export class DefaultTransformer implements android.support.v4.view.ViewPager.IPageTransformer
{
public transformPage(page: android.view.View, position: number): void
{
page.setTranslationX(page.getWidth() * -position);
var yPosition = position * page.getHeight();
page.setTranslationY(yPosition);
}
}
But i do it like that i get this exception:
Error: Cannot convert object to Landroid/support/v4/view/ViewPager$PageTransformer; at index 1
As i had kind of the same issue in Xamarin, then i'm doing this:
export class DefaultTransformer extends java.lang.Object implements android.support.v4.view.ViewPager.IPageTransformer
{
constructor()
{
super();
return global.__native(this);
}
public transformPage(page: android.view.View, position: number): void
{
page.setTranslationX(page.getWidth() * -position);
var yPosition = position * page.getHeight();
page.setTranslationY(yPosition);
}
}
But then i get this exception:
Error: No java object found on which to call "setPageTransformer" method. It is possible your Javascript object is not linked with the corresponding Java class. Try passing context(this) to the constructor function.
I am passing context to the constructor. Any ideas?
_Copied from original issue: NativeScript/NativeScript#2981_
Hey @alexrainman!
First off, what you did with DefaultTransformeer is not how interface implementations work in NativeScript. You can either extend java.lang.Object and decorate the class with @Interfaces([]), or write an inline implementation of the interface. Second off, the interface is just ViewPager.PageTransformer as opposed to ViewPager.*I*PageTransformer
Last, in your ViewPager's implementation constructor you return global.__native(this) this is necessary in typescript to return a reference to the Java Object, otherwise TS would return just a JavaScript wrapper. To be able to work on that Java instance before you've finished constructing the object, you would need to again call the method on the native instance global.__native(this)
global.__native(this).setPageTransformer(false, new android.support.v4.view.ViewPager.PageTransformer({
transformPage(page: android.view.View, position: number): void {
page.setTranslationX(page.getWidth() * -position);
var yPosition = position * page.getHeight();
page.setTranslationY(yPosition);
}
})
or alternatively
@Interfaces([android.support.v4.view.ViewPager.PageTransformer])
export class DefaultTransformer extends java.lang.Object {
transformPage(page: android.view.View, position: number): void { ... }
}
@Pip3r4o thanks for this. I advice you guys to provide examples in your documentation on how to implement interfaces in {N}. Normally i review your code when i try to do new stuff but couldn't find anything in this case. Same with interfaces in iOS, nothing in documentation. Nothing either for what you mention that you have to return global.__native(this) in Android. Also, i see in tab-view where you use ViewPager, you use something like this:
var PageAdapterClass;
function ensurePageAdapterClass() {
if (PageAdapterClass) {
return;
}
...
}
I am using same thing but i don't know why. Do i need to the same in my custom viewpager or in the PageTransformer implementation?
Thanks
@Pip3r4o also, i cannot add @Interfaces([android.support.v4.view.ViewPager.PageTransformer]) decoration to my class, TypeScript says it cannot find Interfaces name. What i am missing here?
@alexrainman We try to make the docs as clear as possible, but that is an ongoing effort, and we need the community's help, to assist us in writing a better documentation.
Extending classes and implementing interfaces - https://docs.nativescript.org/runtimes/android/generator/extend-class-interface#implementing-multiple-interfaces-in-nativescript
If you feel like something can be improved - please do Improve this Article. Links can be found at the beginning of every article.
And about what you find in our modules - we do extra checks and optimizations, which very often is not necessary to do on the casual user's end.
If you cannot find @Interfaces decorator it is likely that you don't have the tns-core-modules's package typings. Add https://github.com/NativeScript/NativeScript/commit/7bde7f5d5cabea5b2eda9110c0640d2121605621 manually as a work around. That should also be available in tns-core-modules@next builds and will certainly be available in version 2.4
@Pip3r4o don't understand me wrong, you guys are doing an amazing job and you always help the community to solve issues like this. That's why i am putting time and effort building a plugin i know the community will love. Version 1 is already out and version 2 is on the way https://www.npmjs.com/package/nativescript-carousel-view
@Pip3r4o can you use some of your valuable time to answer my question about this?
var PageAdapterClass;
function ensurePageAdapterClass() {
if (PageAdapterClass) {
return;
}
...
}
Is this a common practice? Why is needed? Do i need to do the same with my custom viewpager class and page transformer?
@alexrainman not at all! And I am more than happy to help out community members if it means building better and more stable apps for them!
Regarding the last question -> I believe it's some kind of optimization, or rather a safeguard, don't believe the casual NS user will ever have to do that. It might depend on your application logic and the order in which things are initialized. @hshristov may know more
@Pip3r4o as im building a plugin, i am following same practices i see in your code base :)
Most helpful comment
Hey @alexrainman!
First off, what you did with DefaultTransformeer is not how interface implementations work in NativeScript. You can either extend java.lang.Object and decorate the class with @Interfaces([]), or write an inline implementation of the interface. Second off, the interface is just
ViewPager.PageTransformeras opposed toViewPager.*I*PageTransformerLast, in your ViewPager's implementation constructor you return
global.__native(this)this is necessary in typescript to return a reference to the Java Object, otherwise TS would return just a JavaScript wrapper. To be able to work on that Java instance before you've finished constructing the object, you would need to again call the method on the native instanceglobal.__native(this)or alternatively