Jssor slider manual transition trigger - slider

Is it possible to have manual trigger for transitions from one slide to another.
If I use $JssorArrowNavigator$, it does slide to next/previous, but without transitions.
Adding custom actions $PlayTo, $GoTo, $Next also just slides to next, but without transition.
$Play starts the slideshow with the transitions but there is some initial lag of ~10s.

Slideshow transition plays only for 'auto play'.
While auto play, you can assign transition for specific slide.
function SlideParkEventHandler(slideIndex, fromIndex)
{
if(slideIndex == 0)
{
jssor_slider1.$SetSlideshowTransitions([{transition_code1}]);
}
else if(slideIndex == 1)
{
jssor_slider1.$SetSlideshowTransitions([{transition_code2}]);
}
else
{
jssor_slider1.$SetSlideshowTransitions([{transition_code3}, {transition_code4}, ...]);
}
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, SlideParkEventHandler);

Related

Drag gestures inside scrollable control

I've made a custom control based around a Canvas. It uses two .pointerInput modifiers, one to detect click and one to detect drag so the user can toggle a column of 50 buttons, either by clicking on one at a time or dragging across a number of them to set them all at once. It works well, and now I'd like to have a horizontally scrollable Row containing a number of these. The immediate problem is that the Row, when the .horizontalScroll modifier is applied, swallows vertical movement as well, and even taps, so although I can scroll through a number of controls I'm no longer able to interact with them.
The only example I can find that's similar is the nested scrolling in the Gestures documentation, but that's between two controls using scrolling, and although the outer control is clearly not preventing the inner control receiving events it's not clear how to apply it in my case.
Without pasting huge quantities of code, I'm defining the Row by
#Composable
fun ScrollBoxes() {
Row(
modifier = Modifier
.background(Color.LightGray)
.fillMaxSize()
.horizontalScroll(rememberScrollState())
) {
repeat(20) {
Column {
Text(
"Item $it", modifier = Modifier
.padding(2.dp)
.width(500.dp)
)
JetwashSlide(
model = JetwashSlideViewModel()
)
}
}
}
}
and the modifier of the Canvas is my custom control is set up as
modifier
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { ... }
},
onDragEnd = { ... },
onDrag = { change, dragAmount ->
change.consumeAllChanges();
...
}
}
)
}
.pointerInput(Unit) {
detectTapGestures(
onPress = { it ->
...
}
)
}
A crude approach would be to have a scrollable row of labels and use the presently selected label to determine which full width custom control is presently visible. This wouldn't be as aesthetically pleasing as having the controls scrolling horizontally. Does anyone have an idea how this could be achieved?
Ok, my starting point was this tutorial on how to make a scrolling pager from scratch;
https://fvilarino.medium.com/creating-a-viewpager-in-jetpack-compose-332d6a9181a5
Using that, you can get a horizontally scrolling row of instances of a control. The problem is that I wanted horizontal swipes to be handled by the pager, and taps and vertical swipes to be handled by the custom control, and although the custom control gets the gestures if made over the control, it couldn't pass them up to the pager if they were horizontal swipes, so you could only scroll using the gaps between the custom controls. I expected that the control could use .detectVerticalDragGestures and .detectTapGestures and the pager could use .detectHorizontalDragGestures, but it wasn't that simple.
I ended up pulling code from the Jetpack source into my own code so I could modify it to produce my own gesture detector which captures vertical scroll and tap events but does not capture horizontal scroll;
suspend fun PointerInputScope.detectVerticalDragOrTapGestures(
onDragStart: (Offset) -> Unit = { },
onDragEnd: () -> Unit = { },
onDragCancel: () -> Unit = { },
onVerticalDrag: (change: PointerInputChange, dragAmount: Float) -> Unit,
onClick: ((Offset) -> Unit) = { },
model: JetwashSlideViewModel
) {
forEachGesture {
awaitPointerEventScope {
model.inhibitGesture = false
val down = awaitFirstDown(requireUnconsumed = false)
//val drag = awaitVerticalTouchSlopOrCancellation(down.id, onVerticalDrag)
val drag = awaitTouchSlopOrCancellation(
down.id
) { change: PointerInputChange, dragAmount: Offset ->
if (abs(dragAmount.y) > abs(dragAmount.x)) {
//This is a real swipe down the slide
change.consumeAllChanges()
onVerticalDrag(change, dragAmount.y)
}
}
if (model.inhibitGesture) {
onDragCancel()
} else {
if (drag != null) {
onDragStart.invoke(drag.position)
if (
verticalDrag(drag.id) {
onVerticalDrag(it, it.positionChange().y)
}
) {
onDragEnd()
} else {
onDragCancel()
}
} else {
//click.
if (!model.inhibitGesture)
onClick(down.position)
}
}
}
}
}
Now in the pager, it was using .horizontalDrag. This is fine if you can actually drag purely horizontally or purely vertically, but you can't and swipes that were intended to be vertical on the inner control often had a tiny bit of horizontal motion which caused the pager to intercept it. So in the pager, I also had to copy and modify some code to make my own .horizontalDrag;
suspend fun AwaitPointerEventScope.horizontalDrag(
pointerId: PointerId,
onDrag: (PointerInputChange) -> Unit
): Boolean = drag(
pointerId = pointerId,
onDrag = onDrag,
motionFromChange = { if (abs(it.positionChangeIgnoreConsumed().x) > 10) it.positionChangeIgnoreConsumed().x else 0f },
motionConsumed = { it.positionChangeConsumed() }
)
This only triggers if the horizontal component of the movement is larger than 10px.
Finally, since a horizontal scroll may also have some element of vertical which could affect the inner controls, in my onPagerScrollStart and onPagerScrollFinished callbacks I set and clear a flag in the model, inhibitGesture which causes the inner control to disregard gestures that it happens to get while the pager is in the process of being scrolled.

How do I make the observe function work more than once?

I'm trying to create a slider that will update every time a slide is altered. I've got it set to observe, observeParents, and observeChildren, and it works the first time I show or hide slides, but it's only working once. Is there a good workaround for this?
Here's a link to the page with the slider on it. Click the color swatches to see what I'm talking about. Thanks in advance!
I figured out a workaround! I added a data-element called data-slides that updates on the container when you click to make the slideshow change, like so.
thumbnails.each(function() {
var wrapper = $(this);
container = $('.swiper-container');
color = colorLabel.val();
while (wrapper.parent().children().length === 1) {
wrapper = wrapper.parent();
}
if (jQuery(this).attr('alt') === optionValue) {
wrapper.fadeIn('500').show();
container.attr('data-slides', color);
} else {
wrapper.fadeOut('500').hide();
}
});
It triggers the observe function and allows it to update as necessary.

Angular material 7: Cannot correctly select radio buttons inside component using keyboad

I'm developing an app with Ionic 4/Angular 7/Angular Material 7.
In a screen there's a stepper.
Inside each stepper there's complex forms. Given its complexity I put this form inside components.
Inside the second step there's a radio group. When I open the second step I can set focus on a radio with keyboard, but can't select a radio button. The radio button get a grey circle around but not the color of selection.
In the first step there's also a radio group and in the initial state I can select it using keyboard. But if I open the second step and open the first step again the radio buttons are not selectable too.
I've simulated the situation without components inside the steppers and I was not able to reproduce the problem this way. Then I deduce the problem is caused by the component inside a step after this step is open.
How can I be able to correctly select the radio buttons inside a step?
Palliatively solved through a directive:
import { Directive, HostListener } from '#angular/core';
import { MatRadioButton } from '#angular/material';
#Directive({
selector: 'mat-radio-button'
})
export class MatRadioCorrectionDirective {
constructor(private host:MatRadioButton) { }
#HostListener('keyup', ['$event'])
onKeyup(event: KeyboardEvent) {
// console.log(event);
if(
event.keyCode == 38 // arrow up
|| event.keyCode == 40 // arrow down
|| event.keyCode == 37 // arrow left
|| event.keyCode == 39 // arrow right
) {
event.preventDefault();
this.host.checked = true;
// TODO: send event
this.host.change.emit(null);
// setTimeout(() => {
// }, 500);
}
}
}

jssor slider different transitions

I have 5 different slides, the first four slides with the same transition, only the last slide should act with a different transition.
I have defined the transitions in the _SlideshowTransitions arrays, shown here:
var _SlideshowTransitions = [
{$Duration:1000,$Opacity:2,$Brother:{$Duration:800,$Opacity:2}},
{$Duration:1000,$Opacity:2,$Brother:{$Duration:800,$Opacity:2}},
{$Duration:1000,$Opacity:2,$Brother:{$Duration:800,$Opacity:2}},
{$Duration:1000,$Opacity:2,$Brother:{$Duration:800,$Opacity:2}},
{$Duration:1200,x:-0.3,$During:{$Left:[0.3,0.7]},$Easing:{$Left:$JssorEasing$.$EaseInCubic,$Opacity:$JssorEasing$.$EaseLinear},$Opacity:2}
];
Works great as long as you do not use the navigation arrows or bullets! How can I allocate the one different transition to the one special slide ?
thanks in advance
JD
You can use api $SetSlideshowTransitions to set slideshow transitions dynamically anytime.
var jssor_slider1 = new $JssorSlider$("slider1_container", options);
function SetSlideshowTransition() {
switch (jssor_slider1.$CurrentIndex()) {
case 3:
jssor_slider1.$SetSlideshowTransitions([{$Duration:1200,x:-0.3,$During:{$Left:[0.3,0.7]},$Easing:{$Left:$JssorEasing$.$EaseInCubic,$Opacity:$JssorEasing$.$EaseLinear},$Opacity:2}]);
break;
default:
jssor_slider1.$SetSlideshowTransitions([{$Duration:1000,$Opacity:2,$Brother:{$Duration:800,$Opacity:2}}]);
break;
}
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, SetSlideshowTransition);

Back button on first level of nestedlist

I have a nestedList with a few levels that appears when the user presses a button on the screen. When the nestedList appears, there is no back button (because we're at the top of the tree, so understandably there is nowhere to go back to), whereas tapping on items in the list takes you to screens with a back button.
I'd like to add a back button to the first screen. I have managed to do this, but not without adding the same back button to every sublist in the nestedList - this has the effect of 1 back button at the top level, and 2 back buttons (one to take you out of the nestledList completely, and one to take you up a level) at every subsequent level.
Can anyone help me figure out how to have 1 back button on each screen, including the top level to close the list?
Many thanks
PS a nasty workaround that I'm using at the moment is to have a "close" button in the top right of every screen instead.
I don't know how comfortable you are with the inner workings of Sencha Touch so how you go about doing this is up to you--
The back button is there, hidden, when the nested list is shown (created in the initComponent function with hidden: true), and then onBackTap, onItemTap and setActivePath will all call syncToolbar near the end of their functions which is where the back button is hidden when you are at a depth of 0.
So there are 2 places you need to do something about, first is initComponent which is easy-- just implement initComponent in your nestedList, call the superclass' initComponent and then set the backButton visible
var myNestedList = new Ext.NestedList({
...,
initComponent: function() {
myNestedList.superclass.initComponent.call(this);
this.backButton.setVisible(true);
},
...
});
That takes care of showing it intially.. how you care to deal with fixing syncToolbar is up to you. You can use Ext.override, you can straight up copy and paste the whole syncToolbar function into your nestedList object which would also override it or you could do what you're told never to do and just edit the sencha-touch.js file directly. However you decide to do it, what you're looking to change is
syncToolbar: function(card) {
...
backToggleMth = (depth !== 0) ? 'show' : 'hide';
if (backBtn) {
backBtn[backToggleMth]();
if (parentNode) {
backBtn.setText(backBtnText);
}
}
... };
You can either change backToggleMth to = 'show' or just delete the if (backBtn {...} all together.
In the Sencha Touch 2.2 I had to use a different code:
Ext.create('Ext.NestedList', {
...,
listeners: {
initialize: function(obj) {
obj.getBackButton().show();
},
back: function(obj, node, lastActiveList, detailCardActive) {
switch(node.getDepth()) {
case 1:
obj.getBackButton().show();
break;
case 0:
alert("wohooooooo!");
break;
}
}
}
}