How can we check application is going to be exit in OnBackButtonPressed()
protected override bool OnBackButtonPressed()
{
//Exit form application?
base.OnBackButtonPressed();
return false;
}
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (await DisplayAlert("", "Exit the application?", "Yes", "No"))
{
if (Device.RuntimePlatform == Device.Android)
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
else if (Device.RuntimePlatform == Device.iOS)
{
Thread.CurrentThread.Abort();
}
}
});
return true;
}
Related
I have implemented a custom web view renderer in Droid project.
How can I redirect the Phone Dialer from WebView when I click on a phone number in WebView?
Any help is appreciated. Thanks!
You can try the following code:
public class MyWebViewRenderer : WebViewRenderer
{
public MyWebViewRenderer(Context context) : base(context) { }
static MyWebView _xwebView = null;
WebView _webView;
class ExtendedWebViewClient : Android.Webkit.WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
var tel = "tel:";
if (url != null)
{
if (url.StartsWith(tel))
{
var uri = Android.Net.Uri.Parse(url);
var intent = new Intent(Intent.ActionView, uri);
intent.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
return true;
}
}
return false;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
_xwebView = e.NewElement as MyWebView;
_webView = Control;
if (e.OldElement == null)
{
_webView.SetWebViewClient(new ExtendedWebViewClient());
}
}
}
And for the ios part:
public class MyWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationDelegate = new MyWKNavigationDelegate();
}
class MyWKNavigationDelegate : WKNavigationDelegate
{
[Export("webView:decidePolicyForNavigationAction:decisionHandler:")]
public override void DecidePolicy(WKWebView webView, WKNavigationAction
navigationAction, Action<WKNavigationActionPolicy> decisionHandler)
{
var navType = navigationAction.NavigationType;
var targetFrame = navigationAction.TargetFrame;
var url = navigationAction.Request.Url;
if (
url.ToString().StartsWith("http") && (targetFrame != null &&
targetFrame.MainFrame == true)
)
{
decisionHandler(WKNavigationActionPolicy.Allow);
}
else if (
url.ToString().StartsWith("mailto:")
|| url.ToString().StartsWith("tel:")
|| url.ToString().StartsWith("Tel:"))
{
UIApplication.SharedApplication.application.OpenUrl(url);
}
}
}
}
I have implemented the nullable date picker to show the placeholder to date field as well as the null date in it, You can see the code below
Now the issue here is when I click on the current date then the DateSelected event is not getting trigger, it triggers when you select the previous date or next dates but not getting selected for the current date.
Thanks in advance.
NDateControl.cs
public class NDatePicker : DatePicker
{
public NDatePicker()
{
Format = "MM'/'dd'/'yyyy";
}
public string _originalFormat = null;
public static readonly BindableProperty PlaceHolderProperty =
BindableProperty.Create(nameof(PlaceHolder), typeof(string), typeof(c), "'MM/DD/YYYY'");
public string PlaceHolder
{
get { return (string)GetValue(PlaceHolderProperty); }
set { SetValue(PlaceHolderProperty, value); }
}
public static readonly BindableProperty NullableDateProperty =
BindableProperty.Create(nameof(NullableDate), typeof(DateTime?), typeof(NDatePicker), null, defaultBindingMode: BindingMode.TwoWay);
public DateTime? NullableDate
{
get { return (DateTime?)GetValue(NullableDateProperty); }
set
{
SetValue(NullableDateProperty, value);
UpdateDate();
}
}
private void UpdateDate()
{
if (NullableDate != null)
{
if (_originalFormat != null)
{
Format = _originalFormat;
}
}
else
{
Format = PlaceHolder;
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext != null)
{
_originalFormat = Format;
UpdateDate();
}
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == DateProperty.PropertyName || (propertyName == IsFocusedProperty.PropertyName
&& !IsFocused && (Date.ToString(Constant.DATE_FORMAT) == DateTime.Now.ToString(Constant.DATE_FORMAT))))
{
AssignValue();
}
if (propertyName == NullableDateProperty.PropertyName && NullableDate.HasValue)
{
Date = NullableDate.Value;
if (Date.ToString(_originalFormat) == DateTime.Now.ToString(_originalFormat))
{
//this code was done because when date selected is the actual date the"DateProperty" does not raise
UpdateDate();
}
}
}
public void AssignValue()
{
NullableDate = Date;
UpdateDate();
}
}
NDatePickerDroid.cs
public class NDatePickerDroid : ViewRenderer<NDatePicker, EditText>
{
DatePickerDialog _dialog;
public NDatePickerDroid(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<NDatePicker> e)
{
base.OnElementChanged(e);
SetNativeControl(new EditText(Context));
if (Control == null || e.NewElement == null)
return;
Control.TextSize = 14;
Control.Click += OnPickerClick;
Control.Text = Element.Date.ToString(Element.Format);
Control.KeyListener = null;
Control.FocusChange += OnPickerFocusChange;
Control.Enabled = Element.IsEnabled;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Xamarin.Forms.DatePicker.DateProperty.PropertyName || e.PropertyName == Xamarin.Forms.DatePicker.FormatProperty.PropertyName)
SetDate(Element.Date);
}
void OnPickerFocusChange(object sender, Android.Views.View.FocusChangeEventArgs e)
{
if (e.HasFocus)
{
ShowDatePicker();
}
}
protected override void Dispose(bool disposing)
{
if (Control != null)
{
Control.Click -= OnPickerClick;
Control.FocusChange -= OnPickerFocusChange;
if (_dialog != null)
{
_dialog.Hide();
_dialog.Dispose();
_dialog = null;
}
}
base.Dispose(disposing);
}
void OnPickerClick(object sender, EventArgs e)
{
ShowDatePicker();
}
void SetDate(DateTime date)
{
Control.Text = date.ToString(Element.Format);
Element.Date = date;
}
private void ShowDatePicker()
{
CreateDatePickerDialog(Element.Date.Year, Element.Date.Month - 1, Element.Date.Day);
_dialog.Show();
}
void CreateDatePickerDialog(int year, int month, int day)
{
NDatePicker view = Element;
_dialog = new DatePickerDialog(Context, (o, e) =>
{
view.Date = e.Date;
((IElementController)view).SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
Control.ClearFocus();
_dialog = null;
}, year, month, day);
_dialog.SetButton(Constant.DONE, (sender, e) =>
{
SetDate(_dialog.DatePicker.DateTime);
Element.Format = Element._originalFormat;
Element.AssignValue();
});
}
}
NDatePickeriOS.cs
public class NDatePickeriOS : DatePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (e.NewElement != null && Control != null)
{
AddClearButton();
Control.Font = Control.Font.WithSize(14);
Control.BorderStyle = UITextBorderStyle.Line;
Control.Layer.BorderColor = UIColor.LightGray.CGColor;
Control.Layer.BorderWidth = 1;
if (Device.Idiom == TargetIdiom.Tablet)
{
Control.Font = UIFont.SystemFontOfSize(25);
}
}
}
private void AddClearButton()
{
UIToolbar originalToolbar = Control.InputAccessoryView as UIToolbar;
if (originalToolbar != null && originalToolbar.Items.Length <= 2)
{
var clearButton = new UIBarButtonItem(Constant.CLEAR, UIBarButtonItemStyle.Plain, ((sender, ev) =>
{
NDatePicker baseDatePicker = Element as NDatePicker;
Element.Unfocus();
Element.Date = DateTime.Now;
//baseDatePicker.CleanDate();
}));
var newItems = new List<UIBarButtonItem>();
foreach (var item in originalToolbar.Items)
{
newItems.Add(item);
}
newItems.Insert(0, clearButton);
originalToolbar.Items = newItems.ToArray();
originalToolbar.SetNeedsDisplay();
}
}
}
The XAML is
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" Margin="0,2" HeightRequest="60">
<control:NDatePicker NullableDate="{Binding DateAnswer}" DateSelected="DateChanged" HorizontalOptions="FillAndExpand" VerticalOptions="Center"/>
</StackLayout>
You could use MessagingCenter to send a message to your page when you select the current date.
_dialog.SetButton(Constant.DONE, (sender, e) =>
{
SetDate(_dialog.DatePicker.DateTime);
Element.Format = Element._originalFormat;
Element.AssignValue();
if (_dialog.DatePicker.DateTime == DateTime.Today)
{
MessagingCenter.Send<Object,DateTime>(this, "SameDate", view.Date);
}
});
in your page.xaml.cs:
public YourPage()
{
InitializeComponent();
MessagingCenter.Subscribe<Object,DateTime>(this, "SameDate", (sender,args) =>
{
DateTime dateTime = args; //triggered here
});
}
I'm facing some issue with Slide menu in Masterdetail page. I want to disable the functionality in iOS.
In Android, I'm able to disable. But, in iOS it's not working.
"IsGestureEnabled="False" - This Property is working in Android. But not in iOS.
Please help me out this issue.
It seems an existing,and you can use CustomRenderer . Here is a workaround .However , this workaround seems obsolete because of the update of Xamarin.So we can improve it .
[assembly: ExportRenderer (typeof(MasterDetailPage), typeof(ExtendedMasterDetailPageRenderer), UIUserInterfaceIdiom.Phone)]
namespace Core.iOS.Renderers
{
public class ExtendedMasterDetailPageRenderer : PhoneMasterDetailRenderer
{
private MasterDetailPage page;
public ExtendedMasterDetailPageRenderer ()
{
}
// add following override method
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
((MasterDetailPage)this.Element).PropertyChanged += HandlePropertyChanged;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
((MasterDetailPage)this.Element).PropertyChanged += HandlePropertyChanged;
}
private void HandlePropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == MasterDetailPage.IsGestureEnabledProperty.PropertyName)
{
var panGesture = typeof(PhoneMasterDetailRenderer).GetField ("panGesture", BindingFlags.NonPublic | BindingFlags.Instance).GetValue (this) as UIPanGestureRecognizer;
var hasPanGesture = false;
if (panGesture != null)
{
for (int i = 0; i < this.View.GestureRecognizers.Length; i++)
{
if (this.View.GestureRecognizers [i] is UIPanGestureRecognizer)
{
hasPanGesture = true;
break;
}
}
if (((MasterDetailPage)this.Element).IsGestureEnabled)
{
if (!hasPanGesture)
{
this.View.AddGestureRecognizer (panGesture);
}
return;
}
if (hasPanGesture)
{
this.View.RemoveGestureRecognizer (panGesture);
}
}
}
}
}
}
And in your MasterDetailPage
protected override void OnAppearing()
{
base.OnAppearing();
IsGestureEnabled = false;
}
Update
Create a CustomRenderer of Page
[assembly: ExportRenderer(typeof(Page), typeof(MyPageRenderer), UIUserInterfaceIdiom.Phone)]
namespace xxx.iOS
{
class MyPageRenderer : PageRenderer
{
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (this.NavigationController != null)
{
var items = this.NavigationController.NavigationBar.Items;
if(items.Length > 0)
{
UIBarButtonItem leftItem = items[0].LeftBarButtonItem;
if(this.NavigationController.ViewControllers.Length == 1)
{
leftItem.Enabled = false;
}
}
}
}
}
}
I'm using ZXing.Mobile.Forms to scan the barcodes.
I would like to turn the torch on while scanning the barcodes. I tried ToggleTorch() but i dont see the torch light.
Please help to overcome this scenario.
Here is my code:
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
scanner.ToggleTorch();
var option = new ZXing.Mobile.MobileBarcodeScanningOptions { UseCode39ExtendedMode = true, TryHarder = true, PureBarcode = true, };
var result = await scanner.Scan(option);
if (result != null)
await Application.Current.MainPage.DisplayAlert(title, result.Text, "Cancel");
await Application.Current.MainPage.Navigation.PopAsync(true);
OK here is the main idea which does what you want, in an MVVM manner:
XAML:
<zxing:ZXingScannerView x:Name="ScannerView"
IsTorchOn="{Binding IsTorchOn}"
IsScanning="{Binding IsScanning}"
IsAnalyzing="{Binding IsAnalyzing}"
ScanResultCommand="{Binding OnScanResult}"/>
Code-behind:
public partial class BarcodeScannerPage
{
private BarcodeScannerPageModel _pageModel;
public BarcodeScannerPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
if(_pageModel == null) return;
_pageModel.IsScanning = true;
_pageModel.IsAnalyzing = true;
_pageModel.IsTorchOn= true;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
_pageModel = BindingContext as BarcodeScannerPageModel;
}
}
Page model:
public class BarcodeScannerPageModel
{
#region instance variables
private bool _isScanning;
private bool _isAnalyzing;
private bool _isTorchOn;
#endregion
public BarcodeScannerPageModel()
{
IsTorchOn = true;
}
public bool IsScanning
{
get => _isScanning;
set
{
_isScanning = value;
RaisePropertyChanged();
}
}
public bool IsAnalyzing
{
get => _isAnalyzing;
set
{
_isAnalyzing = value;
RaisePropertyChanged();
}
}
public ICommand OnScanResult
{
get
{
return new Command(async (result) =>
{
if (result.ToString().IsNullOrEmpty()) return;
Device.BeginInvokeOnMainThread(async () =>
{
IsAnalyzing = false;
//your code here...
});
});
}
}
public bool IsTorchOn
{
get => _isTorchOn;
set
{
_isTorchOn = value;
RaisePropertyChanged();
}
}
}
Here I assumed MVVM is set and used correctly including "PropertyChanged" events and setting "BindingContext". More info:
MVVM
From Data Bindings to MVVM
MVVM & Data Binding with Xamarin.Forms
Using some MVVM frameworks such as FreshMvvm can make things easier.
React.Native has plugins like react-native-qrcode-scanner.
How can I do that on Weex?
Here comes a solution named EMAS. like weex-market, there are a lot of components and modules. One of these is the scan component which meets your requirement.
But the portal website is only in the Chinese language now.
Here is an android demo using ZXing to do qrcode. Copy this and register as a scan component. Have a look at this Demo.
public class WXQRCodeScannerComponent extends WXComponent<ZXingScannerView> implements ZXingScannerView.ResultHandler{
private static final String VF_WIDTH = "vfWidth";
private static final String VF_HEIGHT = "vfHeight";
private static final String VF_TOP_MARGIN = "vfTopMargin";
private static final String AUTO_STOP = "autoStop";
private static final String ON_SCAN = "scan";
private static final String TAG = "scan";
private boolean isAutoStop = false;
private boolean hasScanned = false;
private Handler mHandler = new Handler(Looper.getMainLooper());
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0x1001;
private OnRequestPermissionCallback mPermissionCallback = new OnRequestPermissionCallback() {
#Override
public void onPermissionGranted() {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#Override
public void onPermissionDenied() {
// nope
}
};
public WXQRCodeScannerComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
super(instance, dom, parent);
}
public WXQRCodeScannerComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, int type) {
super(instance, dom, parent, type);
}
#Override
protected ZXingScannerView initComponentHostView(#NonNull Context context) {
requestPermissionIfNeeded();
ZXingScannerView qrCodeView = new ZXingScannerView(context);
qrCodeView.setSquareViewFinder(true);
qrCodeView.setResultHandler(this); // Register ourselves as a handler for scan results.
return qrCodeView;
}
private void requestPermissionIfNeeded() {
Context c = getContext();
if(c != null && c instanceof Activity) {
if(ContextCompat.checkSelfPermission(c, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) c, Manifest.permission.CAMERA)) {
Toast.makeText(c, "请授予相机权限以用于扫码", Toast.LENGTH_LONG).show();
}
LocalBroadcastManager.getInstance(c)
.registerReceiver(new InnerReceiver(mPermissionCallback), new IntentFilter(WXModule.ACTION_REQUEST_PERMISSIONS_RESULT));
ActivityCompat.requestPermissions((Activity) c,
new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
} else {
//Nope
}
}
}
static class InnerReceiver extends BroadcastReceiver{
private OnRequestPermissionCallback mCallback;
InnerReceiver(OnRequestPermissionCallback callback) {
this.mCallback = callback;
}
#Override
public void onReceive(Context context, Intent intent) {
int code = intent.getIntExtra(WXModule.REQUEST_CODE, 0);
int[] grantResults = intent.getIntArrayExtra(WXModule.GRANT_RESULTS);
String[] permissions = intent.getStringArrayExtra(WXModule.PERMISSIONS);
if(code == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限申请成功
if(mCallback != null) {
mCallback.onPermissionGranted();
}
} else {
Toast.makeText(context, "相机权限申请失败!将无法使用扫码功能!", Toast.LENGTH_SHORT).show();
if(mCallback != null) {
mCallback.onPermissionDenied();
}
}
}
LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
}
}
interface OnRequestPermissionCallback {
void onPermissionGranted();
void onPermissionDenied();
}
#Override
protected boolean setProperty(String key, Object param) {
switch (key) {
case VF_WIDTH:
Float width = WXUtils.getFloat(param,null);
if(width != null) {
setVfWidth(width);
}
return true;
case VF_HEIGHT:
Float height = WXUtils.getFloat(param,null);
if(height != null) {
setVfHeight(height);
}
return true;
case VF_TOP_MARGIN:
Float topMargin = WXUtils.getFloat(param,null);
if(topMargin != null) {
setVfTopMargin(topMargin);
}
return true;
case AUTO_STOP:
Boolean autoStop = WXUtils.getBoolean(param, false);
if(autoStop != null) {
setAutoStop(autoStop);
}
return true;
}
return super.setProperty(key, param);
}
#Override
protected void onHostViewInitialized(ZXingScannerView host) {
super.onHostViewInitialized(host);
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#WXComponentProp(name = VF_WIDTH)
public void setVfWidth(float width) {
float finalWidth = WXViewUtils.getRealSubPxByWidth(width,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setRectWidth((int) finalWidth);
// }
}
}
#WXComponentProp(name = VF_HEIGHT)
public void setVfHeight(float height) {
float finalHeight = WXViewUtils.getRealSubPxByWidth(height,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setRectHeight((int) finalHeight);
// }
}
}
#WXComponentProp(name = VF_TOP_MARGIN)
public void setVfTopMargin(float topMargin) {
float finalTopMargin = WXViewUtils.getRealSubPxByWidth(topMargin,getInstance().getInstanceViewPortWidth());
if(getHostView() != null) {
// ScanBoxView scanBoxView = getHostView().getScanBox();
// if(scanBoxView != null) {
// scanBoxView.setTopOffset((int) finalTopMargin);
// }
}
}
#WXComponentProp(name = AUTO_STOP)
public void setAutoStop(boolean autoStop) {
this.isAutoStop = autoStop;
}
#Override
public void onActivityResume() {
super.onActivityResume();
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.startCamera();
}
}
#Override
public void onActivityPause() {
super.onActivityPause();
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.stopCamera(); // Stop camera on pause
}
}
#Override
public void onActivityDestroy() {
if(mHandler != null) {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.stopCamera();
}
mHandler.removeCallbacksAndMessages(null);
}
}
#Override
public void handleResult(Result result) {
if(isAutoStop && hasScanned) {
resumeCameraPreviewDelayed();
return;
}
fireEventByResult(result);
resumeCameraPreviewDelayed();
hasScanned = true;
}
private void fireEventByResult(Result result) {
if(result == null || TextUtils.isEmpty(result.getText())) {
Map<String,Object> callback = new HashMap<>(4);
callback.put("result","failed");
fireEvent(ON_SCAN,callback);
if(WXEnvironment.isApkDebugable()) {
WXLogUtils.d(TAG, "scan failed");
}
} else {
Map<String,String> data = new HashMap<>(4);
data.put("timestamp", System.currentTimeMillis()+"");
data.put("code", result.getText());
Map<String,Object> callback = new HashMap<>(4);
callback.put("result","success");
callback.put("data", data);
fireEvent(ON_SCAN,callback);
if(WXEnvironment.isApkDebugable()) {
WXLogUtils.d(TAG, "scan success: " + result.getText());
}
}
}
private void resumeCameraPreviewDelayed() {
if(mHandler == null) {
return;
}
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
ZXingScannerView hostView = getHostView();
if(hostView != null) {
hostView.resumeCameraPreview(WXQRCodeScannerComponent.this);
}
}
}, 1000);
}
}