Xamarin Forms - TapGestureRecognizer not working for iOS - ios

I am creating list of image in a loop and attaching
a TapGestureRecognizer to each of them to run a method. It is working on Android but not on iOS. Why is that? Is there a problem with it being in a Grid or in a ScrollView?
Here is my code:
foreach (var i in files)
{
Image image = new Image { Aspect = Aspect.AspectFit };
image.Source = ImageSource.FromUri(new System.Uri(i));
Button button = new Button();
link = i;
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) =>
{
ViewImage(i);
};
image.GestureRecognizers.Add(tapGestureRecognizer);
gridy.Children.Add(image, 0, num);
num++;
}
Here is my Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YHTS.Gallery"
Title="Gallery"
BackgroundColor="Black">
<ScrollView >
<Grid x:Name="gridy">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
</Grid>
</ScrollView>

set InputTransparent="True" of the View

Related

Xamarin forms iOS UIView Renderer intermittent OnElementChanged in some cases

I am doing video matrix views (1x1-2x2-3x3 views) using FlowListView. For iOS app, UIView renderer is used to integrate with a third party video SDK.
Here is the FlowListView.
<flv:FlowListView x:Name="VideoFlowList" FlowColumnCount="{Binding ColumnCount}" RowHeight="{Binding RowHeight, Mode=TwoWay}"
SeparatorVisibility="None" HasUnevenRows="false" BackgroundColor="Transparent"
FlowColumnMinWidth="80" FlowTotalRecords="{Binding TotalRecords, Mode=TwoWay}" FlowItemsSource="{Binding Items}">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid x:Name="VideoGrid" Padding="2" BackgroundColor="{Binding SelectedBorderColour, Mode=TwoWay}" RowSpacing="1" ColumnSpacing="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<video:CameraView x:Name="MyCameraView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Black" />
<Image x:Name="AddIcon" Source="panel_add.png" Grid.Row="0" Grid.Column="0" IsVisible="{Binding CameraNotAssigned}"
HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit" BackgroundColor="Transparent" WidthRequest="50" HeightRequest="50">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AddCameraCommand, Source={x:Reference BrowseItemsPage}}"
CommandParameter="{x:Reference VideoGrid}" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Label x:Name="Label" HorizontalOptions="Fill" HorizontalTextAlignment="Center" VerticalOptions="End"
BackgroundColor="Silver" Opacity="0.5" Text="{Binding CameraName, Mode=TwoWay}" TextColor="Black"/>
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
On the startup of the matrix views, it displays 4 views (ColumnCount = 2, ToTalRecords = 4) in the view model) and works everytime. Switching to any other views works too. But ocassionaly when switching to 4 views from a single view, there are only 2 new Elements instead of 4 in overrided OnElementChanged. How to ensure to get 4 new Elements everytime?
Please note that this issue doesn't happen when switching to 4 views from 9 views.
Here is the code of the ViewRenderer.
public class VideoRender : ViewRenderer<CameraView, UIVideoView>
{
private UIVideoView _videoView;
protected override void OnElementChanged(ElementChangedEventArgs<CameraView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
//Unsubscribe
_videoView.Tapped -= OnVideoViewTapped;
Log.Debug($"OldElement CameraIndex {e.OldElement.CameraIndex}, PlayWndHandle {e.OldElement.PlayWndHandle}");
}
if (e.NewElement != null)
{
//Control is TNativeView, CameraView
if (Control == null)
{
_videoView = new UIVideoView(Element);
SetNativeControl(_videoView);
}
//Element.PlayWndHandle = Handle;
if (_videoView.Subviews.Length > 0)
{
Element.PlayWndHandle = _videoView.Subviews[0].Handle;
}
App.PlayWndHandles.Add(Element.PlayWndHandle);
Log.Debug($"NewElement CameraIndex {Element.CameraIndex}, PlayWndHandle {Element.PlayWndHandle}");
Log.Debug($"App.PlayWndHandles[{App.PlayWndHandles.Count - 1}]: {Element.PlayWndHandle}");
// Subscribe
_videoView.Tapped += OnVideoViewTapped;
}
}
}
I added a subview in the UIView UIVideoView and play the video in the subview. Is the issue related to the way I use the subview?
void Initialize()
{
//place the video in subview
var subView = new UIView();
subView.UserInteractionEnabled = true;
AddSubview(subView);
if (Subviews.Length > 0)
{
Subviews[0].Frame = new CoreGraphics.CGRect(0, 0, 100, 100);
}
}
It appears that using 4 separate lists of play window handles (one for each matrix size) can overcome the handle management issue. A single view is specially handled by clearing the handles in the list because the handle will always be removed and re-created.

Tap action on stack view not working properly when text field selected for iOS with Nativescript

So I'm using Nativescript to create app for both Android and iOS and I'm having some problems with iOS.
So I have a stack view where I have added a tap action, called "closeKeyboard" (currently just log message to console).
Inside the stack view I have text field.
The problem is that when I press on the text field, the stack view action also gets triggered.
On Android it works as expected - selecting text field doesn't trigger stack view action.
Here is the code for main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo">
<StackLayout tap="closeKeyboard">
<Label class="conf-button-label" text="Netto sum" />
<TextField text="{{ sum }}" hint="Type number" returnKeyType="done" keyboardType="number" keyboardPatter="[0-9]*" returnPress="done" id="sum" col="0" row="0" class=""/>
</StackLayout>
</Page>
Here is a code for main-page.js
var createViewModel = require("./main-view-model").createViewModel;
function onNavigatingTo(args) {
page = args.object;
}
function done(){
console.log('Input Done');
}
function closeKeyboard(page){
console.log('Close Keyboard Tapped');
}
exports.done = done;
exports.closeKeyboard = closeKeyboard;
exports.onNavigatingTo = onNavigatingTo;
Can anyone help me with this?
In case you want to create something like javascript blur event or just to hide keyboard, when you tap outside the TextView, you could set custom gesture for ios using native code. You could review the bellow attached example:
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="loaded">
<StackLayout id="stack">
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
<TextView id="text" text="" hint="Enter some text" backgroundColor="yellow" updateTextTrigger="focusLost"/>
</StackLayout>
</Page>
main-page.js
var createViewModel = require("./main-view-model").createViewModel;
var gestures = require("ui/gestures");
var observableModule = require("data/observable");
var observableObject = new observableModule.Observable();
var TapHandlerImpl1 = (function (_super) {
__extends(TapHandlerImpl1, _super);
function TapHandlerImpl1() {
_super.apply(this, arguments);
}
TapHandlerImpl1.initWithOwner = function (owner) {
var handler = TapHandlerImpl1.new();
handler._owner = owner;
return handler;
};
TapHandlerImpl1.prototype.tap = function () {
this._owner.ios.resignFirstResponder();
};
TapHandlerImpl1.ObjCExposedMethods = {
"tap": { returns: interop.types.void, params: [interop.types.id] }
};
return TapHandlerImpl1;
}(NSObject));
var tapHandler = null;
function loaded(args) {
var page = args.object;
var field = page.getViewById("text");
if (page.ios) {
tapHandler = TapHandlerImpl1.initWithOwner(field)
var recognizer = UITapGestureRecognizer.alloc().initWithTargetAction(tapHandler, "tap");
page.ios.view.addGestureRecognizer(recognizer);
}
field.addEventListener(observableModule.Observable.propertyChangeEvent, function(pcd){
console.log(pcd.eventName.toString() + " " + pcd.propertyName.toString() + " " + pcd.value.toString());
});
page.bindingContext = observableObject; }
exports.loaded = loaded;
However the same problem have been discussed also in this GitHub issue.
I think the only way is to move the closeKeyboard() from Stacklayout to the child view Label. Or you can try to define a separate tap action for the textfield to override the tap action of stacklayout.

Slide Menu For iOS using Alloy With latest Titanium sdk

I want to create a sliding menu on the right side of the screen but all the tutorials and links that I found on internet were using older sdks with navigationGroup.
Can anyone please help me to make it?
<Alloy>
<Window class="container" id="window">
<Require type="view" src="menu" id="menu"></Require>
<View id="displayedView">
<View id="topView">
<View id="viewForBack" onClick="back">
<ImageView id="backButton" >
</ImageView>
</View>
<Label id="headerLabel">
Window Name
</Label>
<View id ="menuButtonView" onTouchstart="showMenu">
<ImageView id="menuButton">
</ImageView>
</View>
</View>
</View>
</Window>
</Alloy>
This is the main window in this we have requires the side menu as a view
<Alloy>
<View id="menu" >
// put the menu view design code here
</View>
</Alloy>
with this the menu view is created first and it is behind the main view of the window we have .
All we have to do is slide the top view to create sliding animation
int menuPosition = 1;
function showMenu()
{
if(menuPosition == 1)
{
var a = Ti.UI.createAnimation();
a.left = "-100%";
a.curve = Ti.UI.ANIMATION_CURVE_EASE_OUT;
a.duration = 500;
$.displayedView.animate(a);
a = null;
$.menuButton.zIndex = 1;
}
else
{
var a = Ti.UI.createAnimation();
a.left = "0%";
a.curve = Ti.UI.ANIMATION_CURVE_EASE_OUT;
a.duration = 500;
$.displayedView.animate(a);
a = null;
$.menuButton.zIndex = 1;
}
menuPosition = -menuPosition;
}
hope this helps

How to construct a settings page similar to the stock one in Windows Phone 7?

When I launch the Windows Phone Settings app, what is presented is a pivot control with a bunch of items on each page. For example, the first item is:
THEME
blue
What is the standard way of creating these items? I want them to have the same font style and look. Is there any control to represent the item above?
Thanks!
It is a ListBox control and a DataTemplate for eacht item. The template defines two TextBox controls, one for the 'title' and one for a 'description/value'. You can set the style for each TextBox.
Edit: here's an example code
<ListBox x:Name="YourListBox" Margin="0" ItemsSource="{Binding YourItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ItemTitle}" TextWrapping="Wrap" Style="{StaticResource PhoneTextTitle2Style}"/>
<TextBlock Text="{Binding ItemValue}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
After playing with this for 2 hours pixel by pixel and using a paint program to compare screenshots with the real thing side by side (there's gotta be a better way!), I found the following solution.
Here is the settings page replicated exactly. I've created a custom user control so that adding an item to xaml is as easy as this:
<MyApp:SettingsItem Label="theme" Sub="blue"/>
Here's the code:
SettingsItem.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace MyApp
{
// This custom control class is to show a standard item in a settings page.
public partial class SettingsItem : UserControl
{
private const string TAG = "SettingsItem";
public SettingsItem()
{
// Required to initialize variables
InitializeComponent();
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register(
"Label",
typeof(string),
typeof(SettingsItem),
new PropertyMetadata(new PropertyChangedCallback
(OnLabelChanged)));
public string Label
{
get
{
return (string)GetValue(LabelProperty);
}
set
{
SetValue(LabelProperty, value);
}
}
private static void OnLabelChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
SettingsItem item = (SettingsItem)d;
string newValue = (string)e.NewValue;
item.m_label.Text = newValue.ToLower();
}
public static readonly DependencyProperty SubProperty =
DependencyProperty.Register(
"Sub",
typeof(string),
typeof(SettingsItem),
new PropertyMetadata(new PropertyChangedCallback
(OnSubChanged)));
public string Sub
{
get
{
return (string)GetValue(SubProperty);
}
set
{
SetValue(SubProperty, value);
}
}
private static void OnSubChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
SettingsItem item = (SettingsItem)d;
string newValue = (string)e.NewValue;
item.m_sub.Text = newValue;
}
}
}
SettingsItem.xaml
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="MyApp.SettingsItem"
d:DesignWidth="428" d:DesignHeight="0">
<Grid x:Name="LayoutRoot" Background="Transparent">
<StackPanel
Orientation="Vertical"
>
<TextBlock
x:Name="m_label"
Text="label"
Style="{StaticResource PhoneTextExtraLargeStyle}"
Margin="0, 18, 0, 0"
/>
<TextBlock
x:Name="m_sub"
Text="Sub"
Style="{StaticResource PhoneTextSubtleStyle}"
TextWrapping="Wrap"
Margin="0, -6, 0, 0"
/>
</StackPanel>
</Grid>
</UserControl>
and here's the page xaml:
<phone:PhoneApplicationPage
x:Class="MyApp.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:MyApp="clr-namespace:MyApp;assembly=MyApp"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<controls:Pivot Title="MY APP" SelectedIndex="0">
<controls:PivotItem
Name="PIVOT_GENERAL"
Margin="0"
Header="settings">
<Grid Margin="26,9,0,0">
<StackPanel>
<MyApp:SettingsItem
Label="theme"
Sub="blue"
/>
<MyApp:SettingsItem
Label="date+time"
Sub="UTC-08 Pacific Time (US + Canada)"
/>
<MyApp:SettingsItem
Label="region+language"
Sub="United States"
/>
</StackPanel>
</Grid>
</controls:PivotItem>
</controls:Pivot>
</Grid>
</phone:PhoneApplicationPage>
My suggestion:
<Button>
<Button.Template>
<ControlTemplate>
<StackPanel>
<TextBlock Text="Label" Style="{StaticResource PhoneTextExtraLargeStyle}" Margin="0 18 0 0"/>
<TextBlock Text="Sub" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0 -6 0 0"/>
</StackPanel>
</ControlTemplate>
</Button.Template>

How to bind an image into ListBoxItem in WPF?

I've tried to bind my image into the listbox i've created, yet it is just not working, can any1 help out with my problems so that i can actually bind the image into "ListBoxItem" as shown in the code below.
Code behind:
public object ImageSource
{
get
{
Image finalImage = new Image();
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri(#"/images/food1.bmp", UriKind.Relative);
logo.EndInit();
finalImage.Source = logo;
return logo;
}
}
XAML:
<ListBox Grid.ColumnSpan="2">
<ListBox.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="100"/>
<EventSetter Event="MouseLeftButtonDown" Handler="DragImage"/>
</Style>
</ListBox.Resources>
<ListBoxItem>
<Image Source="{Binding Path=ImageSource}" Width="197" Height="120" Margin="0,0,0,0" />
</ListBoxItem>
</ListBox>
could be a problem with the imagesource. check if this solves your problem.

Resources