XAMARIN: How to Refresh WebView OnTabReselected? - c#

I'm trying to refresh a WebView when the user reselects a tab that is already selected on Android coding with Xamarin using deprecated Actionbar and TabHost.
I've got this code
public void OnTabReselected(WhatsOnActivity tab, FragmentTransaction ft)
{
WebView whatsOnWebView = FindViewById<WebView>(Resource.Id.webViewWhatsOn);
//tell webview to reload
whatsOnWebView.Reload();
}
and I've tried to put that code into both my MainActivity and inside My WhatsOnActivity
It doesn't crash the app, but it also doesn't reload the tab. In Xamarin, can I use the "WhatsOnActivity" as the tab in my method? I have a feeling that's what I'm doing wrong.. but if I try to use tab ids, they're not recognized by the IDE. Can anyone give me direction on what I've done wrong?
my complete code can be found here:
https://github.com/hexag0d/BitChute_Mobile_Android_a2/blob/2.68/MainActivity.cs
if you're wondering about the context.

Update
Try to set OnClicklistener on your first tab. Set the listener after you add tabs.
TabHost.TabWidget.GetChildAt(0).SetOnClickListener(new MyOnClickListener(tabHost));
And the listener:
public class MyOnClickListener : Java.Lang.Object, IOnClickListener
{
TabHost tabHost;
public MyOnClickListener(TabHost tabHost)
{
this.tabHost = tabHost;
}
public void OnClick(View v)
{
var parentView = ((ViewGroup)((ViewGroup)tabHost.GetChildAt(0)).GetChildAt(1)).GetChildAt(0);
WebView whatsOnWebView = parentView.FindViewById<WebView>(Resource.Id.webViewWhatsOn);
whatsOnWebView.Reload();
tabHost.CurrentTab = 0;
}
}
And the result is:
Original answer
Please try to add an OnTabChangeListener to your TabHost.
For example, In your MainActivity OnCreate():
TabHost tabHost = FindViewById<TabHost>(Android.Resource.Id.TabHost);
tabHost.SetOnTabChangedListener(new MyOnTabChangedListener(tabHost));
And the MyOnTabChangedListener:
public class MyOnTabChangedListener : Java.Lang.Object, IOnTabChangeListener
{
TabHost tabHost;
public MyOnTabChangedListener(TabHost tabHost)
{
this.tabHost = tabHost;
}
public void OnTabChanged(string tabId)
{
if(tabId == "whats_on")
{
var parentView = ((ViewGroup)((ViewGroup)tabHost.GetChildAt(0)).GetChildAt(1)).GetChildAt(0);
WebView whatsOnWebView = parentView.FindViewById<WebView>(Resource.Id.webViewWhatsOn);
whatsOnWebView.Reload();
}
}
}

First off thank you so much to #Billy Liu - MSFT !!! dude is a lifesaver. He knows his Xamarin. Alright, so here's how you can refresh a tab OnClick
//Assemblies
using System;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Widget;
using Android.Webkit;
using static Android.Widget.TabHost;
using static Android.Views.View;
using Android.Views;
//this assembly is your Activities class, which should contain your class instances
using com.xamarin.example.BitChute.Activities;
EDIT: Put these click listeners inside your MainActivity.cs .. the int inside GetChildAt() represents the tab our listener will respond to. int 0 = tab farthest left and they go up 0 .. 1 .. 2 .. etc .. 1 would mean tab second from the left. Each listener will need it's own listener class instance. I'll show two examples in the next block.
TabHost tabHost = FindViewById<TabHost>(Android.Resource.Id.TabHost);
tabHost.Setup();
tabHost.TabWidget.GetChildAt(0).SetOnClickListener(new WhatsOnClickListener(tabHost));
tabHost.TabWidget.GetChildAt(1).SetOnClickListener(new SubsClickListener(tabHost));
tabHost.TabWidget.GetChildAt(2).SetOnClickListener(new DiscoverClickListener(tabHost));
tabHost.TabWidget.GetChildAt(3).SetOnClickListener(new MyChannelClickListener(tabHost));
tabHost.TabWidget.GetChildAt(4).SetOnClickListener(new SettingsClickListener(tabHost));
EDIT: Create a separate ClickActivity.cs file and then add these listeners into it. you will need to create an OnClickListener instance for each tab. This example is only two of the listeners; but if you're using my template, you will need to use these examples to create another 3 listeners.
public class WhatsOnClickListener : Java.Lang.Object, IOnClickListener
{
TabHost tabHost;
//this int will tell the click listener whether to reload the webview or pop 2 root
static int tbC = 0;
public WhatsOnClickListener(TabHost tabHost)
{
//tell the clicklistener which tabhost to use
this.tabHost = tabHost;
}
//this class handles the click event
public void OnClick(View v)
{
//declare the webview and tell our object where to find the XAML resource
WebView webViewWhatsOn = tabHost.CurrentView.FindViewById<WebView>(Resource.Id.webViewWhatsOn);
//...if the CurrentTab != 0 ... we won't fire the Reload() or LoadUrl()
//..without this logic, the app will crash because our WebViews
//.aren't set to an instance of an object
if (tabHost.CurrentTab == 0)
{
//if tbC int is 0, we will reload the page
if (tbC == 0)
{
//tell whatsOnWebView to Reload
webViewWhatsOn.Reload();
//set the int to one so next time webview will pop to root
tbC = 1;
}
//else if the int is 1, we will pop to root on tab 0
else if (tbC == 1)
{
//tell whatsOnWebView to pop to root
webViewWhatsOn.LoadUrl(#"https://bitchute.com/");
//set the tbC int so that next time webview will reload
tbC = 0;
}
}
//if our current tab isn't zero, we need to set CurrentTab to 0
//this line is critical or our tabs won't work when not selected
tabHost.CurrentTab = 0;
}
}
public class SubsClickListener : Java.Lang.Object, IOnClickListener
{
TabHost tabHost1;
static int tbC = 0;
public SubsClickListener(TabHost tabHost1)
{
this.tabHost1 = tabHost1;
}
public void OnClick(View v)
{
if (tabHost1.CurrentTab == 1)
{
WebView subWebView = tabHost1.CurrentView.FindViewById<WebView>(Resource.Id.webViewSubs);
if (tbC == 0)
{
subWebView.Reload();
tbC = 1;
}
else if (tbC == 1)
{
subWebView.LoadUrl(#"https://bitchute.com/subscriptions/");
tbC = 0;
}
}
tabHost1.CurrentTab = 1;
}
}
hope that helps! I've been trying this for a minute.

Related

Xamarin Forms Nested Tabs

I've noticed it's possible to create a mobile app with nested tabs.
Is this possible in Xamarin Forms?
Please see screen shot below:
I can create the bottom tabs on iOS using TabbedPage, but how do I create the nested tabs at the top of the page?
Thank you
The same way you would do on the native app. There are no native nested tabs, so Xamarin can't support it as such thing doesn't exist.
In the native app you have the control at the top (called SegmentedControl on iOS and on Android there is no such control out of the box) where you pick the value and then change the view below manually when it is clicked.
Is this possible in Xamarin Forms?
Yes,of course.You can use CustomRenderer to implement it.Refer to the following code.
in iOS Project . Create a pageRenderer
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using app1;
using app1.iOS;
using UIKit;
using Foundation;
using CoreGraphics;
using ObjCRuntime;
[assembly:ExportRenderer(typeof(MyPage1),typeof(MyPageRenderer))]
namespace app1.iOS
{
public class MyPageRenderer:PageRenderer
{
public MyPageRenderer()
{
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (ViewController != null)
{
NSArray items = NSArray.FromStrings(new string[] { "Courses", "Favourite", "Recent" });
UISegmentedControl segmentedControl = new UISegmentedControl(items)
{
Frame = new CGRect(50, 20, NativeView.Bounds.Width - 100, 35)
};
segmentedControl.SelectedSegment = 0;
segmentedControl.TintColor = UIColor.Red;
segmentedControl.ApportionsSegmentWidthsByContent = true; //Change the width of the segment based on the content of the segment
segmentedControl.AddTarget(this, new Selector("ValueChanged:"), UIControlEvent.ValueChanged);
NativeView.AddSubview(segmentedControl);
}
}
[Export("ValueChanged:")]
void ValueChanged(UISegmentedControl sender)
{
MessagingCenter.Send<Object, int>(this, "ClickSegmentedControl", (int)sender.SelectedSegment);
// switch((int)sender.SelectedSegment){
// case 0:
// break;
// case 1:
// break;
// case 2:
// break;
// default:
// break;
//}
}
}
}
in Forms ,you can subscribe the message .if you want to handle the event in forms when you click the segmented .
public MyPage1()
{
//...
MessagingCenter.Subscribe<Object, int>(this, "ClickSegmentedControl", (sender, arg) =>
{
Console.WriteLine(arg); //arg is num of the segment that you clicked.
});
}

UIPageViewController Xamarin

I need to implement a simple UIPageViewController using Xamarin in Visual Studio 2017 for mac.
As the documentation says in https://developer.xamarin.com/api/type/MonoTouch.UIKit.UIPageViewController/ I need to connect the previous and next views, using UIPageViewControllerDataSource.GetNextViewController and UIPageViewControllerDataSource.GetPreviousViewController from the UIPageViewControllerDataSource delegate, but I'm not clear where should I do that, nor I see any where to do that using the storyboard designer.
The idea to use the UIPageViewController is to add a quick tutorial of 4 pages before advancing to another View, at the last view of the UIPageViewController there would be a button that calls the segway to the next page.
You can add a UIPageViewController in the Storyboard. Configure the style in the Properties window => Widget(Navigation, Transition Style, Spine Location).
Then you can add the DataSource in the corresponding CS file. Add the firstly shown UIViewController using: SetViewControllers(new UIViewController[] { viewController }, UIPageViewControllerNavigationDirection.Forward, true, null);. Please notice that when you set the Spine Location to Mid, this array should contain at least two UIViewControllers. If not, add just one.
but I'm not clear where should I do that, nor I see any where to do
that using the storyboard designer.
When you want to navigate to the next page, the event GetNextViewController() will fire(i.e. first page - second page). And you should return which Controller will show in this event. Also GetPreviousViewController() means which Controller you want to show when navigate back. Here is my sample:
public class MyPageViewDataSource : UIPageViewControllerDataSource
{
List<UIViewController> pageList;
public MyPageViewDataSource(List<UIViewController> pages)
{
pageList = pages;
}
public override UIViewController GetNextViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
{
var index = pageList.IndexOf(referenceViewController);
if (index < pageList.Count - 1)
{
return pageList[++index];
}
else
{
//when navigate to the last page, return null to disable navigate to next.
return null;
}
}
public override UIViewController GetPreviousViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
{
var index = pageList.IndexOf(referenceViewController);
if (index == 0)
{
//when navigate to the first page, return null to disable navigate to previous.
return null;
}
else
{
return pageList[index - 1];
}
}
}
At last set your UIPageViewController's DataSource to this:DataSource = new MyPageViewDataSource(pageList);

Xamarin clickable substring in custom label

I am trying to make it so users can click a certain substring in a label and it would run a method, for example clicking #hashtag would run OpenHashtag(string hashtagand clicking a #taggedUser would run ViewProfile(taggedUser)
I found this tutorial, except I don't want phone numbers or URLs to be clickable, only hashtags and tagged users.
These are the renders its using
Android
[assembly: ExportRenderer(typeof(BodyLabel), typeof(BodyLabelAndroid))]
namespace SocialNetwork.Droid.Renderers
{
public class BodyLabelAndroid : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
var view = (BodyLabel)Element;
if (view == null) return;
TextView textView = new TextView(Forms.Context);
textView.LayoutParameters = new LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
textView.SetTextColor(view.TextColor.ToAndroid());
// Setting the auto link mask to capture all types of link-able data
textView.AutoLinkMask = MatchOptions.All;
// Make sure to set text after setting the mask
textView.Text = view.Text;
textView.SetTextSize(ComplexUnitType.Dip, (float)view.FontSize);
// overriding Xamarin Forms Label and replace with our native control
SetNativeControl(textView);
}
}
}
IOS
[assembly: ExportRenderer(typeof(BodyLabel), typeof(BodyLabeliOS))]
namespace SocialNetwork.iOS.Renderers
{
public class BodyLabeliOS : ViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
var view = (AwesomeHyperLinkLabel)Element;
if (view == null) return;
UITextView uilabelleftside = new UITextView(new CGRect(0, 0, view.Width, view.Height));
uilabelleftside.Text = view.Text;
uilabelleftside.Font = UIFont.SystemFontOfSize((float)view.FontSize);
uilabelleftside.Editable = false;
uilabelleftside.DataDetectorTypes = UIDataDetectorType.All;
uilabelleftside.BackgroundColor = UIColor.Clear;
SetNativeControl(uilabelleftside);
}
}
}
Android:
Instead of using textView.AutoLinkMask = MatchOptions.All
you can use
Linkify.AddLinks method. Define your regular expression (for example, any word which starts with # or #) and it will work.
But on iOS, it is more complicated I think.
There I see two options:
Use WebView. Parse your string and add "<a href" where needed.
Break your text to pieces and add separate labels for each clickable part. If you want to click only hashtags and tagged users you can add the appropriate labels just below the text. Afterwards you can add tap gesture recognizers to handle the clicks.

How to make Tabbed page of many content page with a scroll menu in Xamarin forms?

I want to make a tabbed page with 7 content page (in xamarin forms, NOT in native project). but the menu bar in red (I don't know what this thing is called so I call it menu bar) is not a scroll menu, so the title of each content page is not shown well. Like this:
the thing that I actually have
Somebody knows to make something like this?
thing that I want it to be
Well cannot say much without seeing some code! - but my assumption is that your problem is with your theme...
Open up your 'Tabbar.axml' and change this line of code:
app:tabMode="fixed"
To:
app:tabMode="scrollable"
UPDATE:
Then simply add the new line app:tabMode="scrollable" because by default is "fixed"
Anyways as you requested here is my Tabbar.axml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimaryDark"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="#android:color/white"
app:tabGravity="fill"
app:tabMode="scrollable" />
You can also change this by creating a CustomRednerer. My solution is good if you want to create many tabbed pages in your application and you want to make one of them with scrollable tabs and second with non-scrollable tabs.
Here is code for Droid project:
using Android.Support.Design.Widget;
using App1;
using App1.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.AppCompat;
[assembly: ExportRenderer(typeof(ScrollableTabbedPage), typeof(ScrollableTabbedPageRenderer))]
namespace App1.Droid
{
public class ScrollableTabbedPageRenderer : TabbedPageRenderer
{
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
var tabLayout = child as TabLayout;
if (tabLayout != null)
{
tabLayout.TabMode = TabLayout.ModeScrollable;
}
}
}
}
For Portable project:
using System;
using Xamarin.Forms;
namespace App1
{
public class ScrollableTabbedPage : TabbedPage
{
}
public class App : Application
{
public App()
{
var tabbedPage = new ScrollableTabbedPage();
for (int i = 0; i < 7; i++)
{
tabbedPage.Children.Add(this.GetMyContentPage(i));
}
MainPage = new NavigationPage(tabbedPage);
}
private ContentPage GetMyContentPage(int i)
{
return new ContentPage
{
Title = "Tab number " + i,
Content = new StackLayout
{
Children = {
this.GetMyButton()
}
}
};
}
private Button GetMyButton()
{
var myButton = new Button()
{
Text = "Welcome to Xamarin Forms!",
};
myButton.Command = new Command(() =>
{
myButton.Text = "Start" + DateTime.Now.ToString();
});
return myButton;
}
}
}
And for result you get this:

ToolStripButton disappear from PropertyGrid when user log-in to Windows

I have a problem and scenario is the following:
I've created user control with one component PropertyGrid. To this PropertyGrid I added button (Heximal Mode) to the PropertyGrid's ToolStrip. Everything is fine and works great!
But when this control is shown in form and user press "Windows->Switch User" and logging again with same User Name my button (Heximal Mode) disappear. Also the fourth button which was manually hid appears...
I don't know what happen. Probably windows reload its component on user log-in?
Windows 7 (x64/x86)
public partial class CompProperty : UserControl
{
private System.Windows.Forms.ToolStripButton _tsbMode = null;
public CompProperty()
{
InitializeComponent();
createAdditionalButtons();
}
private void createAdditionalButtons()
{
foreach ( Control control in propertyGrid.Controls )
{
ToolStrip toolStrip = control as ToolStrip;
if ( toolStrip != null )
{
toolStrip.Items[4].Visible = false;
_tsbMode = new System.Windows.Forms.ToolStripButton();
_tsbMode.CheckOnClick = true;
_tsbMode.Checked = true;
_tsbMode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
_tsbMode.Image = Resources.img_edit;
_tsbMode.ImageTransparentColor = System.Drawing.Color.Magenta;
_tsbMode.Name = "tsbMode";
_tsbMode.Size = new System.Drawing.Size( 23, 22 );
_tsbMode.Text = "Heximal Mode";
_tsbMode.ToolTipText = "Heximal Mode";
toolStrip.Items.AddRange( new System.Windows.Forms.ToolStripItem[] {
_tsbMode} );
break;
}
}
}
}
Yes, this is by design. The PropertyGrid class rebuilds the toolbar when the SystemEvents.UserPreferencesChange event fires. Which is indeed likely to fire on a desktop switch. You could patch it like this:
using System;
using System.Windows.Forms;
class MyPropertyGrid : PropertyGrid {
protected override void OnSystemColorsChanged(EventArgs e) {
// Do nothing
}
}
Not ideal of course. Cold hard fact is that this simply isn't supported.

Categories