At the end or beginning of a Sencha Touch 2 carousel, a user can drag the item past where it should be able to go and display the white background (screenshot here: http://i.imgur.com/MkX0sam.png). I'm trying to disable this functionality, so a user can't drag past the end/beginning of a carousel.
I've attempted to do this with the various scrollable configurations, including the setup that is typically suggested for dealing with overscrolling
scrollable : {
direction: 'horizontal',
directionLock: true,
momentumEasing: {
momentum: {
acceleration: 30,
friction: 0.5
},
bounce: {
acceleration: 0.0001,
springTension: 0.9999,
},
minVelocity: 5
},
outOfBoundRestrictFactor: 0
}
The above configuration, especially outOfBoundRestrictFactor does stop the ability to drag past the end, but it also stops the ability to drag anywhere else in a carousel either...so that doesn't work. I've screwed around with all of the other configurations to no positive effect.
Unfortunately, I haven't been able to find much on modifying the configurations of dragging. Any help here would be awesomesauce.
What you need to do is override the onDrag functionality in Carousel. This is where the logic is to detect which direction the user is dragging, and where you can check if it is the first or last item.
Here is a class that does exactly what you want. The code you are interested in is right at the bottom of the function. The rest is simply taken from Ext.carousel.Carousel.
Ext.define('Ext.carousel.Custom', {
extend: 'Ext.carousel.Carousel',
onDrag: function(e) {
if (!this.isDragging) {
return;
}
var startOffset = this.dragStartOffset,
direction = this.getDirection(),
delta = direction === 'horizontal' ? e.deltaX : e.deltaY,
lastOffset = this.offset,
flickStartTime = this.flickStartTime,
dragDirection = this.dragDirection,
now = Ext.Date.now(),
currentActiveIndex = this.getActiveIndex(),
maxIndex = this.getMaxItemIndex(),
lastDragDirection = dragDirection,
offset;
if ((currentActiveIndex === 0 && delta > 0) || (currentActiveIndex === maxIndex && delta < 0)) {
delta *= 0.5;
}
offset = startOffset + delta;
if (offset > lastOffset) {
dragDirection = 1;
}
else if (offset < lastOffset) {
dragDirection = -1;
}
if (dragDirection !== lastDragDirection || (now - flickStartTime) > 300) {
this.flickStartOffset = lastOffset;
this.flickStartTime = now;
}
this.dragDirection = dragDirection;
// now that we have the dragDirection, we should use that to check if there
// is an item to drag to
if ((dragDirection == 1 && currentActiveIndex == 0) || (dragDirection == -1 && currentActiveIndex == maxIndex)) {
return;
}
this.setOffset(offset);
}
});
Related
I've embarrassingly spent the past 2 weeks trying to solve this.
What I'm trying to do is:
Snap my Slide Over View to the bottom of the screen
Disable dragging up and only allow the card to be dragged down to close
What I've tried:
I've tried messing with the size of the card by setting its height to the height of the screen. You can see this line commented out. After doing this, I've messed around with the offset of the card and set it so that it looks as if the card is actually less than half its size, around 300 in height. The problem with this is when I slide up slowly, I can see the empty space that is hidden out of the screen. This isn't the effect I want.
The next thing I have tried to do is change the height of the card to a desired height. Then adjust the offset so the card is where I want it to be. However, I feel manually adjusting it won't be reliable on different screens. So I'm trying to work out the right math needed to always have it be placed at the very bottom of the screen when it pops up.
Finally, I want to just make it so users can only drag down and not up.
I would really appreciate some help here. I've spent a lot of time message around and reading, learning new things, but I can't solve my specific problem.
Here is my Slide Over Card
import SwiftUI
struct SigninView<Content: View> : View {
#GestureState private var dragState = DragState.inactive
#State var position = CardPosition.top
var content: () -> Content
var body: some View {
let drag = DragGesture()
.updating($dragState) { drag, state, transaction in
state = .dragging(translation: drag.translation)
}
.onEnded(onDragEnded)
return Group {
// Handle()
self.content()
}
.frame(height: 333) //UIScreen.main.bounds.height)
.background(Color.purple)
.cornerRadius(10.0)
.shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
.offset(y: self.position.rawValue + self.dragState.translation.height)
.animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
.gesture(drag)
}
private func onDragEnded(drag: DragGesture.Value) {
let verticalDirection = drag.predictedEndLocation.y - drag.location.y
let cardTopEdgeLocation = self.position.rawValue + drag.translation.height
let positionAbove: CardPosition
let positionBelow: CardPosition
let closestPosition: CardPosition
if cardTopEdgeLocation <= CardPosition.middle.rawValue {
positionAbove = .top
positionBelow = .middle
} else {
positionAbove = .middle
positionBelow = .bottom
}
if (cardTopEdgeLocation - positionAbove.rawValue) < (positionBelow.rawValue - cardTopEdgeLocation) {
closestPosition = positionAbove
} else {
closestPosition = positionBelow
}
if verticalDirection > 0 {
self.position = positionBelow
} else if verticalDirection < 0 {
self.position = positionAbove
} else {
self.position = closestPosition
}
}
}
enum CardPosition: CGFloat {
case top = 100
case middle = 790
case bottom = 850
}
enum DragState {
case inactive
case dragging(translation: CGSize)
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .dragging(let translation):
return translation
}
}
var isDragging: Bool {
switch self {
case .inactive:
return false
case .dragging:
return true
}
}
}
Here is my ContentView page, where I test it:
import SwiftUI
struct ContentView: View {
#State var show:Bool = false
var body: some View {
SigninView {
VStack {
Text("TESTING")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
First, you should probably not have your SigninView be your content view. Instead, consider presenting your sign in view as an overlay instead.
var body: some View {
ZStack {
Text("Content here!")
}
.overlay(
SigninView()
.offset(...),
alignment: .bottom
)
}
This will automatically place your view at the bottom of the screen at the height of your SigninView, there should be little to no math involved here. The offset, you will define with your gesture and any space you want to exist between the bottom and your overlay.
Next, to only allow down gestures, can't you just clamp your translation?
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .dragging(let translation):
return max(0, translation) // clamp this to the actual translation or 0 so it can't go negative
}
}
In my detail scroll view, I detect the gesture and go back to previous navigation.
However, The go back will happen immediately. Unlike most app will have a animation to peek/preview the previous view.
How to enable this in react-native?
Also, the swipe right detect is not so user-friendly.
Here's my algorithm.
Any idea to make it more smoothly?
onPanResponderMove(event, gestureState) {
if(event.nativeEvent.changedTouches.length===1){
// x 位移
let diffX = gestureState.dx - this.lastPositionX
if (this.lastPositionX === null) {
diffX = 0
}
// y 位移
let diffY = gestureState.dy - this.lastPositionY
if (this.lastPositionY === null) {
diffY = 0
}
if(diffX > 5 && Math.abs(diffY) < 10 ){
this.props.navigation.goBack()
}
// 保留这一次位移作为下次的上一次位移
this.lastPositionX = gestureState.dx
this.lastPositionY = gestureState.dy
}
}
How to control the vertical scroll using right and left arrow in titanium. How to connect the between the scroll view and right and left arrow
Here is the code:
var counter = 0;
rightArrow.addEventListener('click', function(e) {
counter++;
var wrapperChild = wrapperView.getChildren();
var scroll2 = verticalScroll.scrollTo(114, 0);
var scroll1 = verticalScroll.scrollTo(0, 0);
var scroll3 = verticalScroll.scrollTo(307, 0);
if (counter == 1) {
verticalScroll.scrollTo(114, 0);
alert(counter);
} else if (counter == 2) {
verticalScroll.scrollTo(307, 0);
alert(counter);
//}
} else if (counter == 3) {
verticalScroll.scrollTo(417, 0);
alert(counter);
} else if (counter == 4) {
verticalScroll.scrollTo(560, 0);
alert(counter);
} else if (counter == 5) {
verticalScroll.scrollTo(672, 0);
alert(counter);
}
});
leftArrow.addEventListener('click', function(e) {
if (counter == 0) verticalScroll.scrollTo(0, 0);
});
verticalScroll.addEventListener('scroll', function(e) {
Ti.API.info('Scrollview contents y offset: ' + e.x + 'Scrollview contents y offset: ' + e.y);
});
Scrollview has a method called scrollTo( Number x, Number y ), documented here.
Basically you have to
create and add the scrollview to the window
create and add left and right buttons to the window (you might have to set the zIndex if you add the buttons before the scrollview)
add eventListeners to the buttons that will trigger the scrollTo(). See "Simple Buttons Example"
You might be also interested in Titaniums ScrollableView
I'm looking for a thumbnail tiles scroller/slideshow/slider
Here is the example http://safari.to/clients
Really appreciate if anyone could help :) Thanks
When you see something on any website, its easy to inspect and see how they are doing it.
The website mentioned by you is doing it using their own script instead of a plug in
See the following code from http://safari.to/assets/js/script.js. You will also need to see how they are styling the sliders by inspecting their CSS code
// Agencies slide
var clients = Math.floor(Math.random() * 2) + 1; // nth-child indices start at 1
if ( clients == 1){
$('.agencies.clients').hide();
}
else
{
$('.brands.clients').hide();
}
$('.agencies menu a').bind({
click: function()
{
if(sliding) return false;
var pointer = $(this);
var width = $('.agencies .scroller li').length * 137;
var current = parseInt($('.agencies .scroller').css('left'));
var distance = 0;
if(pointer.is('.right-pointer'))
{
if(current == -1920) distance = current - 137;
else distance = current - 960;
if((width + current) < 960)
distance = current;
}
else
{
distance = current + 1097;
if(distance > 0)
distance = 0;
}
sliding = true;
$('.scroller').animate({
left: distance + 'px'
}, 300,
function()
{
sliding = false;
});
}
});
I want Carousel to stop swiping at start and end of the pages.
I mean to prevent the end page to swipe to the right and the start page to swipe to the left:
Is there any config or some other way to implement it?
Thank you in Advance.
By default, ST2's carousel component has this configuration. So, you need not put in any extra effort to achieve this.
Look at this example from Sencha's website. When you reach the last item, it will prevent swiping to the right and when you are on first item, it will prevent swiping to the left.
Ext.create('Ext.Carousel', {
fullscreen: true,
defaults: {
styleHtmlContent: true
},
items: [
{
html : 'Item 1',
style: 'background-color: #5E99CC'
},
{
html : 'Item 2',
style: 'background-color: #759E60'
},
{
html : 'Item 3'
}
]
});
You can create your own carousel and then override the onDrag event following is the code form Ext.carousel.Carousel
Ext.define('Ext.carousel.Custom', {
extend: 'Ext.carousel.Carousel',
onDrag: function(e) {
if (!this.isDragging) {
return;
}
var startOffset = this.dragStartOffset,
direction = this.getDirection(),
delta = direction === 'horizontal' ? e.deltaX : e.deltaY,
lastOffset = this.offset,
flickStartTime = this.flickStartTime,
dragDirection = this.dragDirection,
now = Ext.Date.now(),
currentActiveIndex = this.getActiveIndex(),
maxIndex = this.getMaxItemIndex(),
lastDragDirection = dragDirection,
offset;
if ((currentActiveIndex === 0 && delta > 0) || (currentActiveIndex === maxIndex && delta < 0)) {
delta *= 0.5;
}
offset = startOffset + delta;
if (offset > lastOffset) {
dragDirection = 1;
}
else if (offset < lastOffset) {
dragDirection = -1;
}
if (dragDirection !== lastDragDirection || (now - flickStartTime) > 300) {
this.flickStartOffset = lastOffset;
this.flickStartTime = now;
}
this.dragDirection = dragDirection;
// now that we have the dragDirection, we should use that to check if there
// is an item to drag to
if ((dragDirection == 1 && currentActiveIndex == 0) || (dragDirection == -1 && currentActiveIndex == maxIndex)) {
return;
}
this.setOffset(offset);
}
});
reference :=Link