I am currently writing a Messenger app for my Guild, currently I got as far as, I can log in and switch between different tabs, that lists currently dummy message titles (like a whisper name).
My goal later is that once you click on one of the messages you can reply / read messages in WhatsApp style (tips welcome here as well).
But my current issue is that I use the "Bottom" navigation menu. I swap the tabs currently with new activies. But whenever I click a button the screen "flickers" like, it's restarting the whole app.
Is there some way to switch "fluid" the upper part of the app, while the menu always stays nicely at the bottom?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
namespace GuildMaster
{
[Activity(Label = "Whisper")]
public class Whisper : Activity, BottomNavigationView.IOnNavigationItemSelectedListener
{
private ListView whisperlist;
private List<string> itemlist;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
BottomNavigationView navigation = FindViewById<BottomNavigationView>(Resource.Id.navigation);
navigation.SetOnNavigationItemSelectedListener(this);
whisperlist = FindViewById<ListView>(Resource.Id.whisper);
itemlist = new List<string>();
itemlist.Add("Tim");
itemlist.Add("Tom");
ArrayAdapter<string> whisper = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, itemlist);
whisperlist.Adapter = whisper;
whisperlist.ItemClick += Listnames_ItemClick;
// Create your application here
}
public void Listnames_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
Toast.MakeText(this, e.Position.ToString(), ToastLength.Long).Show();
}
public bool OnNavigationItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Resource.Id.navigation_home:
StartActivity(typeof(Whisper));
return true;
case Resource.Id.navigation_dashboard:
StartActivity(typeof(Guild));
return true;
case Resource.Id.navigation_notifications:
StartActivity(typeof(Other));
return true;
}
return false;
}
}
}
you should try working with fragments instead of activities with the bottom navigation, working with an activity means u have to start a completely new screen with a new bottom navigation, if that is what you are doing then it is completely normal to "flicker" when doing so
as a solution, use an activity with an xml that holds a fragment view and a bottom navigation view, and when u switch from the bottom navigation in your activity, switch the fragments loaded within the fragment view.
this can be done with different methods, but i would suggest checking out the Navigation Component from Google, since it will also handle the backstack for you.
Related
I'm still fairly new to Visual Studio/Xamarin but I had a simple OpenStreetMap sample running awhile ago for Android that did display a map but that doesn't seem to display map anymore though I haven't changed the code for this sample in awhile as far as I recall. I'm not sure if some Visual Studio/Xamarin or MacOS update might have caused it to not work anymore.
I'm using Visual Studio for Mac community 8.4.4 (build 91) on macOS Mojava 10.14.6 and the following Packages:
Mapsui 1.4.8
OsmSharp 6.2.0
Xamarin.Android.Support.Core.Utils 28.0.0.1
Xamarin.Android.Support.CustomTabs 28.0.0.1
Xamarin.Android.Support.Design 28.0.0.1
Xamarin.Essentials 1.2.0
My MainActivity.cs file contains the following code:
using System;
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
using Mapsui;
using Mapsui.Geometries;
using Mapsui.Projection;
using Mapsui.Styles;
using Mapsui.Utilities;
using Mapsui.UI.Android;
using Mapsui.Widgets.ScaleBar;
using Mapsui.Widgets.Zoom;
using Xamarin.Essentials;
namespace mvp_android
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme.NoActionBar", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.Main);
var mapControl = FindViewById<MapControl>(Resource.Id.mapcontrol);
var map = new Mapsui.Map();
map.Layers.Add(OpenStreetMap.CreateTileLayer());
map.Widgets.Add(
new ZoomInOutWidget(map) {
HorizontalAlignment = Mapsui.Widgets.HorizontalAlignment.Left,
VerticalAlignment = Mapsui.Widgets.VerticalAlignment.Top,
Orientation = Mapsui.Widgets.Zoom.Orientation.Horizontal,
}
);
var centerOfLondonOntario = new Point(-81.2497, 42.9837);
map.NavigateTo(SphericalMercator.FromLonLat(centerOfLondonOntario.X, centerOfLondonOntario.Y));
map.NavigateTo(map.Resolutions[9]);
mapControl.Map = map;
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.menu_main, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
int id = item.ItemId;
if (id == Resource.Id.action_settings)
{
return true;
}
return base.OnOptionsItemSelected(item);
}
private void FabOnClick(object sender, EventArgs eventArgs)
{
View view = (View)sender;
Snackbar.Make(view, "Replace with your own action", Snackbar.LengthLong)
.SetAction("Action", (Android.Views.View.IOnClickListener)null).Show();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
And my Main.xml contains the following code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Mapsui.UI.Android.MapControl
android:id="#+id/mapcontrol"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Originally, this sample showed the OpenStreetMap's map centering on the London, Ontario location with zoom in/out buttons, but now it just shows a white where the map should be, still shows the zoom in/out buttons and does display the (c)OpenStreetMap watermark.
What am I missing here?
Update 2021-03-23: Since last week the "BruTile Tile Library" user agent is blocked by OpenStreetMap. This is the default of BruTile's KnownTileSource.Create. This method has a parameter to pass in your own user agent. The fix is to provide a string that is specific to your app.
The version of BruTile used in Mapsui 1.4.8 did not send the user-agent as part of it's request and at some point the openstreetmap server started blocking requests for this reason.
As a workaround you could create a custom ITileSource as described here by Matt Schneeberger:
https://github.com/Mapsui/Mapsui/issues/668#issuecomment-497947690
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.
});
}
I want to use a disclosure button on my table view cell. Therefore I use this custom renderer:
using HelloXamarinFormsWorld;
using HelloXamarinFormsWorld.iOS;
using UIKit;
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using System.Drawing;
using ObjCRuntime;
/* Example of using a custom renderer to get the > disclosure indicator to appear */
[assembly: ExportRenderer (typeof (EmployeeCell), typeof (EmployeeCellRenderer))]
namespace HelloXamarinFormsWorld.iOS
{
public class EmployeeCellRenderer : ViewCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell (item, reusableCell, tv);
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
// // Remove seperator inset
// if (cell.RespondsToSelector (new Selector ("setSeparatorInset:"))) {
// cell.SeparatorInset = UIEdgeInsets.Zero;
// }
// // Prevent the cell from inheriting the Table View's margin settings
// if (cell.RespondsToSelector (new Selector ("setPreservesSuperviewLayoutMargins:"))) {
// cell.PreservesSuperviewLayoutMargins = false;
// }
// // Explictly set your cell's layout margins
// if (cell.RespondsToSelector (new Selector ("setLayoutMargins:"))) {
// cell.LayoutMargins = UIEdgeInsets.Zero;
// }
return cell;
}
}
}
If I set the disclosure indicator I get the following screen:
Normally it does look like the following
I tried to play with the inset, but that has to be in WillDisplay and also the indentation is not removed. In this thread rmarinho states
you can fix by setting the UIEdgeInsets i think , i use the Padding property on ExtendedViewCell for this.
but I don't know where I should do this. Or how do I fix the indentation?
Edit:
Using cell.SeparatorInset = new UIEdgeInsets(0,0,0,0); didn't help.
I guess it should be a bug in Xamarin.Forms.
After looking into the decompiled code, I have found that the default ViewCellRenderer tries to center itself by calculating the content view of the cell, which is not correct as it didn't consider the size of DisclosureIndicator.
So, the workaround is to insert an indicator manually (that's what ExtendedViewCell did) and do not use the default disclosure indicator.
I am using a windows phone user control to show a popup. I used this because My app may be calling for a log in # several points(not if already logged in). I was able to display the popup(used a class). This is my first time exposure to mobile apps. What I need is to disable the page from which the popup is called and enable it once we are logged in or cancelled the popup. Please find my code below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Controls.Primitives;
namespace Project1.Utilies
{
class TALogin
{
public void display_cspopup()
{
Popup popup = new Popup();
popup.Height = 300;
popup.Width = 400;
popup.VerticalOffset = 200;
Pages.PopupController control = new Pages.PopupController();
popup.Child = control;
popup.IsOpen = true;
control.popuplgnbtn.Click += (s, args) =>
{
popup.IsOpen = false;
};
control.popupcnclbtn.Click += (s, args) =>
{
popup.IsOpen = false;
};
}
}
}
AS you may have guessed, PopupController is the controller created for Popup UI(xaml file).
Thanks,
Akhil
what you can do is have two secondary Grids in your Primary Grid and set the visibility to visible or collapsed as per you require!!
your xaml should look somewhat like this:
<Grid x:name="ParentGrid">
<Grid x:name="ChildGrid1">
<!-- your work -->
</Grid>
<Grid x:name="ChildGrid2">
<!-- your work -->
</Grid>
</Grid>
assume you have a button in your grid, on its click event you can collapse any of the grids in this manner!!
//in click event of the button:
ChildGrid1.Visibility=Visibility.Collapsed;
Hope this helps!! :)
I am working on this custom control. (I am very new to this part of programming.) I am working on an application that has to be able to format mathematical expressions as the user enters the input in my own custom control. This is how I want the control to look like (this image is made in Photoshop):
I will not explain the behavior I want it to have, because this doesn't help you, but the idea is that it is not based on any Windows Control.
Tis is the code I already have:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Support.Components
{
public partial class PartialExpressionEditor : Control
{
public PartialExpressionEditor()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Brush background = Brushes.White;
pe.Graphics.FillRectangle(background, ClientRectangle);
background.Dispose();
}
}
}
When I try to put it in my form, I get this error dialog:
Where is the problem? Or why this error appears?
I think the problem is that you are disposing a system brush:
// background.Dispose();
since you didn't create it:
Brush background = Brushes.White;
To use your own brush that you dispose yourself:
using (SolidBrush br = new SolidBrush(Color.White)) {
pe.Graphics.FillRectangle(br, this.ClientRectangle);
}
You might have to exit Visual Studio to get your Brushes.White brush back.