Appcelerator TableViewRow swipe - tableview

Does anyone know of a hack to allow for a left->right swipe on a tableviewrow. The default swipe action opens a delete button however I require additional buttons but want to maintain the same UX but the "swipe" event listener doesn't seem to fire on rows.
myTblRow.addEventListener('swipe', function(e){
Titanium.API.info("huzzah, a row was swiped");
});
The above == no dice.

It does require a bit of a hack.. remove the editable property on the tableView declaration.
The hack is to apply a view that covers the tableRow:
var row1 = Titanium.UI.createView({
width: Titanium.Platform.displayCaps.platformWidth,
height: 145,
zIndex: 100,
opacity: 0.1
});
row.add(row1);
Notice the zIndex, the opacity makes it exist but be totally transparent.
You now need to create a 'swipe' event listener:
tableView.addEventListener('swipe', function(e){
tableView.updateRow(e.index, createUpdateRow(e.source.myProperty), {
animationStyle: Titanium.UI.iPhone.RowAnimationStyle.LEFT
});
});
When the event fires, createUpdateRow() is called, which returns a tableRow. This tableRow you add all of your custom buttons to, you can change the height of the row, anything. The animation style property will mean if you swipe from the right > left, the new row will animate in from the left, which is an effect I like..
Hope this helps, anyone else.. The extra View (row1) is what got me for ages!

Related

Nativescript - how to get layout to open on a tap

I've got a StackLayout where one of the entries is a GridLayout of a fixed size. Normally this GridLayout is not visible.
On tapping a button, I'd like the GridLayout be made visible - but I'd like to animate it open - - like a menu open.
Any ideas?
Actually toggling visibility is not too bad - it seems to animate the open - any way to control the speed?
The close operation is maybe too fast for what I'm trying to achieve.
You could animate the opacity of your grid. so when you click on it you would
// View is your gridView, this would hide it completely
view.opacity = 0;
// when you want to show it.
// fade in view.
view.animate({
opacity: 1,
duration: 250
}).then(() => {
//Set the visibility to collapsed after the animation is complete
//I believe you will want to do this so that the surrounding views adjust accordingly.
view.visibility='collapse';
}, (err) => {});
// when you want to hide it.
// fade out.
view.animate({
opacity: 0,
duration: 250
}).then(() => {
view.visibility='visible';
}, (err) => {});
You also may want to look into translate for you animations so you can move view down, left, up, right any way you want.

In React Native - How to move View element in parallely while ScrollView scrolls

I'm developing a TimeLine component. There are Views list inside horizontal ScrollView that represents half an hour blocks. And I have a Component called TimeRangeSelector, which I use to select a range of time in TimeLine ScrollView. So while I scroll the ScrollView I need to move the TimeRangeSelector in parallel without any lag. Below is the TimeLine component. You can see the 30mins blocks are filled inside ScrollView. The yellow color one is the TimeRangeSelector which is a Animated.View. And the left position of the TimeRangeSelector is set using the scroll position. Each time ScrollView moves im setting the state as below.
<ScrollView
horizontal={true}
onScroll={this.onScrollFunc}
>
{timelineElements}
</ScrollView>
onScrollFunc = (event, gesture) => {
this.setState({
contentOffsetX: event.nativeEvent.contentOffset.x,
scrollStopped: false
});
};
And Im passing the scrollBarPosition as props to the TimeRangeSelector and setting its left position style as shown in below code
<TimeRangeSelector
scrollBarPosition={this.state.contentOffsetX}
/>
let styles= [
{
position: "absolute",
left: this.props.scrollBarPosition,
backgroundColor: backgroundColor,
marginTop: 20,
marginLeft: 1,
width: this.state.selectionWidth,
height: 100
}
];
But the issue is when I scroll the ScrollView the TimeRangeSelector moves with it, but it has a delay.. when I scroll faster the distance between where it should be and where it is, is becoming high. Can anyone give me some ideas according to your knowledge.
My assumption: According to my understanding, I think the lag is because of it takes several instances to reach the setState in and set the ScrollBarPosition as below steps.
ScrollView moved 1 frame.
ScrollView fires the onScroll function and emmits the event with new x point.
Then in the onScroll function it sets the State.
As I understand it takes some time to happen all these steps from JavaScript thread all the way to Native Thread and come back to JS thread again.
You should use something like const onScroll = Animated.event([{ nativeEvent: { contentOffset: { x: animatedValue } } }], { useNativeDriver: true }); with const animatedValue = new Animated.Value(0). This way the animation is only done on the native level without going back and forth through the JS thread.
This animated value can only be used effectively with opacity and transform style properties, but it should help you with your problem.
You can read more about this, in this awesome article.

Click event on view not firing in Titanium Appcelerator

In my controller, I populate a TableView with rows dynamically by building up an array of TableViewRow and populating it with a View & Image.
Here's the code that creates the View & ImageView and a click event on the view:
// Create product image view
var productImageView = Titanium.UI.createView({
borderRadius: 5,
left: 10,
top: 10,
bottom: 10,
width: 130,
backgroundColor: '#FFFFFF',
productName: Name,
imageUrl: ThumbnailUrl,
});
productImageView.add(Titanium.UI.createImageView({
backgroundColor: '#FFFFFF',
defaultImage: 'image-missing',
image: ThumbnailUrl
}));
productImageView.addEventListener('click', function(e) {
if (e.source.productName && e.source.imageUrl) {
Alloy.createController('view_product_image', { ProductName: e.source.productName, ImageUrl: e.source.imageUrl }).getView().open({
modalTransitionStyle: Ti.UI.iPhone.MODAL_TRANSITION_STYLE_COVER_VERTICAL,
modalStyle: Ti.UI.iPhone.MODAL_PRESENTATION_FORMSHEET
});
} else {
console.log('data not set');
}
});
When this code runs, within the table row, I can see the image. When I click it, nothing happens. I tried attaching the click event on the ImageView directly also but still nothing happens.
Any ideas why the click event is not getting fired? Should I be subscribing to a different event instead?
You are not receiving click event because your event source is imageview and it has no productName and imageUrl property.
To receive click event of view, you need to set touchEnabled property to false of your image view.
productImageView.add(Titanium.UI.createImageView({
backgroundColor: '#FFFFFF',
defaultImage: 'image-missing',
image: ThumbnailUrl,
touchEnabled :false
}));
however I think instead of adding a listener to each view you can add a common Listener to tableView and handle the event based on e.source.productName property as suggested by others.
I tried your code and it works for me on iOS and Android.
Maybe, can you show the TableView creation?
However, although your solution is correct, it is preferable and more efficient to add a event listener at your TableView not inside a TableViewRow due the number of listeners that will be created, then to reduce the scope of your click event only to the image, You check if the e.source has the productName and imageURL properties (e.g), otherwise you can infer that the click was outside the image.
Try like this:
$.tableView.addEventListener('click', function(e) {
if (e.source.productName && e.source.imageUrl)
console.log('hit')
});

Hammer.js breaks vertical scroll when horizontal pan

I'm using Hammer.js to look for horizontal pan gestures, I've devised a simple function to clicks a button when panned left or right. It works okay, except the vertical scroll doesn't do anything on a touch device, or it's really glitchy and weird.
Here's the function:
var panelSliderPan = function() {
// Pan options
myOptions = {
// possible option
};
var myElement = document.querySelector('.scroll__inner'),
mc = new Hammer.Manager(myElement);
mc.add(new Hammer.Pan(myOptions));
// Pan control
var panIt = function(e) {
// I'm checking the direction here, my common sense says it shouldn't
// affect the vertical gestures, but it blocks them somehow
// 2 means it's left pan
if (e.direction === 2) {
$('.controls__btn--next').click();
// 4 == right
} else if (e.direction === 4) {
$('.controls__btn--prev').click();
}
};
// Call it
mc.on("panstart", function(e) {
panIt(e);
});
};
I've tried to add a horizontal direction to the recognizer but it didn't really help (not sure if I did it even right):
mc = new Hammer.Manager(myElement, {
recognizers: [
[Hammer.Pan,{ direction: Hammer.DIRECTION_HORIZONTAL }],
]
});
Thanks!
Try setting the touch-action property to auto.
mc = new Hammer.Manager(myElement, {
touchAction: 'auto',
recognizers: [
[Hammer.Pan,{ direction: Hammer.DIRECTION_HORIZONTAL }],
]
});
From the hammer.js docs:
When you set the touchAction to auto it doesnt prevent any defaults, and Hammer would probably break. You have to call preventDefault manually to fix this. You should only use this if you know what you're doing.
User patforna is correct. You need to adjust the touch-action property. This will fix scrolling not working when you have hammer bound on a big element in mobile.
You create a Hammer instance like so
var h = new Hammer(options.contentEl, {
touchAction : 'auto'
});
I was working on a pull to refresh feature, so I need the pan event.
Add the recognizers.
h.get( 'pan' ).set({
direction : Hammer.DIRECTION_VERTICAL,
});
h.on('panstart pandown panup panend', eventHandler);
Inside the eventhandler, you'd look at the event that was triggered and manually call on event.preventDefault() when you require it. This is applicable for hammer 2.0.6.
For anyone who's looking the pull to refresh code was taken from - https://github.com/apeatling/web-pull-to-refresh
My problem was that vertical scroll was toggling a sidebar that was supposed to show/hide on horizontal pan/swipe. After looking at the event details, I realized that Hammer probably triggers panleft and panright event based on X delta and doesn't consider Y delta, so my quick solution was to check the pan direction in my handler:
this.$data.$hammer.on('panleft', (e) => {
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
return;
}
this.isVisible = true;
});
I was stuck on this for several days. Hope this will fix your problem.
mc = new Hammer(myElement, {
inputClass: Hammer.SUPPORT_POINTER_EVENTS ? Hammer.PointerEventInput : Hammer.TouchInput,
touchAction: 'auto',
});
When the relevant gesture is triggered, we applied a css class to the element, that would set the touch-action to none.
mc.on('panmove panstart', event => {
mc.addClass('is-dragging');
}
);
.is-dragging {
touch-action: none !important;
}
Hammer 2.x does not support vertical swipe/pan. Documentation says:
Notes:
When calling Hammer() to create a simple instance, the pan and swipe recognizers are configured to only detect horizontal gestures
You can however use older 1.1.x version, which supports vertical gestures
——
Clarification: this refers to a ‘simple instance’ which is when you don’t pass in any recognizer configuration as the second parameter. In other words these are the defaults but can (and usually should) be overridden.

jquery easing with animate

i have a page that shows a div on mouseover i want the page to move to the div on focus....i got help here to do that...
Now i want the onfocus to the div to move with the easing plugin and move it. i dont want to use the 'slow' in the animate e.g
$('html, body').animate({ scrollTop: $('#box0').offset().top }, 1000);
how can i apply easing to the above code
Secondly i want the div that is showing to slide out from left to right on mouseenter and slide right to left before hiding.
this is what i am using for now. I know there is a better or best way to achieve what i am doing right now.
$("#app0").mouseenter(function () {
$("#lSection2").show('slide').delay(3000); //container for div of four
$("#boxContent0").slideDown(2000);$('html, body').animate({ scrollTop: $('#app0').offset().top }, 1000);// one of the divs within #lSection2
});
$('#boxContent0').mouseleave(function() {
$("#boxContent0").fadeOut(1000);
$("#lSection2").fadeOut(1000);
});
Thanks for your help
The easing can be added as follow, see http://api.jquery.com/animate/
.animate( properties [, duration] [, easing] [, complete] )
You can use hover for mouseover and mouseout.
$("#app0").hover(function () {
// Mouseover
$("#lSection2").stop(true, false).width(0).animate({ width: 200}, 1000);
},function(){
// Mouseout
$("#lSection2").stop(true, false).width(0).animate({ width: 0}, 1000);
});
The stop is needed otherwise mouseover, mouseout, will complete the first animation and then the next and the next and the next, this way you can stop the animation and continue with the next.

Resources