I am writing an app with Xamarin.Android and MvvmCross. I am using fragments and have a "content container" design where I show the fragments in my content_frame view:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</FrameLayout>
Everything works, and I can navigate through my app by showing/closing the fragments in my content_frame, but when I close the last fragment, instead of closing the app, it shows a blank screen instead. I reckon I can fix this in my MvxAppCompatViewPresenter class but I don't know how? I currently don't have anything in my view presenter:
public class ViewPresenter : MvxAppCompatViewPresenter
{
public ViewPresenter(IEnumerable<Assembly> androidViewAssemblies) : base(androidViewAssemblies)
{
}
public override void Show(MvxViewModelRequest request)
{
base.Show(request);
}
public override void Close(IMvxViewModel viewModel)
{
base.Close(viewModel);
}
}
Here is the first fragment:
[MvxFragmentPresentation(typeof(LoginViewModel), Resource.Id.content_frame, true)]
[Register("myapp.droid.fragments.LoginSelectionFragment")]
public class LoginSelectionFragment : BaseFragment<LoginSelectionViewModel>
{
protected override int FragmentId => Resource.Layout.fragment_login_selection;
}
One of the approaches you can use, is to not add the fragments that are starting fragments to the backstack by setting the MvxFragmentPresentation property AddToBackStack to false (false is also the default if no parameter is passed).
The idea there is that for the first fragment you would rely on the activity being added to the backstack. Essentially, the first fragment and the activity could then be considered the same with respect to the backstack, eliminating the blank screen.
However, this would only work if the starting fragments do not need to be added to the backstack, with in the same activity context, later in the navigational flow. In future versions of MvvmCross you would easily be able to overcome this limitation via the updated IMvxOverridePresentationAttribute.
Related
I am using ContentView inside a ContentPage like this
<ContentView x:Name="MyContent"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ContentView.GestureRecognizers>
<SwipeGestureRecognizer Swiped="SwipLeft" Direction="Left"/>
<SwipeGestureRecognizer Swiped="SwipRight" Direction="Right"/>
</ContentView.GestureRecognizers>
</ContentView>
in the code behind I set the relavent Content to the ContentView according to the SwipeDirection like below. and same as for SwipRight.
private void SwipLeft(object sender, SwipedEventArgs e)
{
if (e.Direction == SwipeDirection.Left)
{
//set the relavent page content here
}
}
I need to set an animation or transition to appear when I swipe between pages. I need this only for iOS. Can anyone help me for this or any method knows anyone to achieve this?
you can get the idea from this snapshot
click here for image
all the content and everything has done I just need to add transitions between pages.
You could use the TabbedPage . It seems that you want to let the tab display on the top of screen . In your case you could install the plugin TopTabbedPage from nuget .
Usage
<forms:TopTabbedPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Naxam.Demo.TestPage"
xmlns:views="clr-namespace:Naxam.Demo"
xmlns:forms="clr-namespace:Naxam.Controls.Forms;assembly=Naxam.TopTabbedPage.Forms"
BarTextColor="#00b9e1"
BarIndicatorColor="#00b9e1"
BarBackgroundColor="#ffffff"
Title="MyRide">
<views:Page1 /> // here is the content page , you need to put each contentview in independent ContenPage
<views:Page2 />
</forms:TopTabbedPage>
And in iOS project -> AppDelegate.cs
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
TopTabbedRenderer.Init();
Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
For more details about the plugin you could refer the github project site .
In C# Xamarin Android projects, I am trying to create a custom compound component to select a month. This extends LinearLayout.
I expect to re-use it (and keep my main project more tidy), so I have 2 projects - my main/parent project, containing my Activity and multiple Fragments; and a simple Android project for my component.
When I run the component project directly using its own Activity, it works as expected, but when I reference it from my main project, my FindViewById return null.
I can see that this and context are from the main project - and I would like to understand what I've done wrong or what I need to add so that it finds the component's layout and controls to inflate?
Main view (Ui.DateScrollPicker.Droid is my component's namespace and ScrollMonthPicker my class):
<?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"
android:paddingLeft="10dp"
android:paddingRight="10dp">
.......
<ui.datescrollpicker.droid.ScrollMonthPicker
android:id="#+id/my_scroll_month_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Referenced from a Android.Support.V4.App.Fragment in the override View OnCreateView method:
scrollMonthPicker = view.FindViewById<ScrollMonthPicker>(Resource.Id.scroll_month_picker);
scrollMonthPicker.DateChanged += DatePicker_Changed;
By extending LinearLayout, I am implementing 2 constructors, including, ScrollMonthPicker(Context context, IAttributeSet attrs) : base(context, attrs, 0) which is called, and goes off to inflate my component's layout.
Component view (scroll_month_layout.axml):
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="#+id/month_current_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Month" />
<TextView
android:id="#+id/year_current_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Year" />
<android.support.v7.widget.RecyclerView
android:id="#+id/month_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</merge>
ScrollMonthPicker constructor:
public ScrollMonthPicker(Context context, IAttributeSet attrs)
: base(context, attrs, 0)
{
InflateLayout(context, attrs);
}
ScrollMonthPicker inflating view:
private void InflateLayout(Context context, IAttributeSet attrs)
{
var inflater = LayoutInflater.FromContext(this.Context);
inflater.Inflate(Resource.Layout.scroll_month_layout, this);
monthCurrentText = FindViewById<TextView>(Resource.Id.month_current_text);
yearCurrentText = FindViewById<TextView>(Resource.Id.year_current_text);
monthRecyclerView = FindViewById<RecyclerView>(Resource.Id.month_recycler_view);
monthRecyclerView.HasFixedSize = true;
......
}
The component works fine when called from 'its own' Activity, but all FindViewById are null (monthCurrentText, yearCurrentText and monthRecyclerView) when referenced by the fragment in the main project.
If I wait for the exception to be thrown in the main fragment from monthRecyclerView.HasFixedSize, I do not get a null reference exception, but this one:
Unhandled Exception:
System.NotSupportedException: Could not activate JNI Handle 0x7fff30d40b00 (key_handle 0x8f4c53e) of Java type 'md53fd9f663a5e8ddcd0a5da1b57d05fd99/ScrollMonthPicker' as managed type 'Ui.DateScrollPicker.Droid.ScrollMonthPicker'.
How do I make it populate as expected by referencing from a separate project??
Many thanks.
It seems your both projects are the android project. You could not use another android project code in one project. I think you need to create your CustomComponent project as a library.
I am new to MVVMCross framework for Android and having trouble on how to enable/disable a button. I wasn't able to find a documentation around this area.
Code ViewModel:
private bool _buttonEnabled;
public bool ButtonEnabled
{
get
{ return string.IsNullOrEmpty(EmailLogin);}
set
{
_buttonEnabled = value;
RaisePropertyChanged(() => ButtonEnabled);
}
}
Android axml:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/Login"
android:background="#color/yellow"
local:MvxBind="Enabled(ButtonEnabled)"/>
But unable to get it to work. What I'm trying to achieve is that if EmailLogin variable is NullOrEmpty then button should be disabled. Where am i going wrong ?
Hopefully i'm not pushing this but can i add additional binding to it so that if it is disabled or enabled i can change the color of the button ?
You just need to change the binding syntax to this:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/Login"
android:background="#color/yellow"
local:MvxBind="Enabled ButtonEnabled"/>
I don't know if you are doing it because your code doesn't show everything, but you will also need to call RaisePropertyChanged(() => ButtonEnabled); inside the setter of your EmailLogin property.
Also if you want to change the color of your button, you can install the official color plugin. Usage would be something like this:
private MvxColor _myColor;
public MvxColor MyColor
{
get
{ return _myColor; }
set
{
_myColor = value;
RaisePropertyChanged(() => MyColor);
}
}
And then: local:MvxBind="Enabled ButtonEnabled; TextColor MyColor"
Is it possible to add a layout to the MvxSplashScreenActivity? I have overiden the OnViewModelSet like in all the other activities and placed the following code:
protected override void OnViewModelSet()
{
base.OnViewModelSet ();
SetContentView (Resource.Layout.SplashScreen);
}
The layout I am trying to load is:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minWidth="25px"
android:minHeight="25px">
<ImageView
android:src="#drawable/applogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView1"
android:layout_centerInParent="true" /></RelativeLayout>
and I am getting the following exception:
Cirrious.CrossCore.Exceptions.MvxException: Failed to resolve type
Cirrious.MvvmCross.Binding.BindingContext.IMvxBindingContextStack`1[[Cirrious.MvvmCross.Binding.Droid.BindingContext.IMvxAndroidBindingContext,
Cirrious.MvvmCross.Binding.Droid, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]
I cant seem to find anything online regarding the mvvmcross splash screen..
Ahy Ideas?
You can't use a databound layout within the splashscreen - the splashscreen is displayed before mvvmcross is fully started.
However, for a simple layout, you do pass a resource Id down to the base class constructor:
public class SplashScreen : MvxSplashScreenActivity
{
public SplashScreen()
: base(Resource.Layout.SplashScreen)
{
}
}
Further - to avoid black start screens - most people use a theme to specify a whole screen image in their splashscreen - see the 'standard' splash screen supplied by nuget - https://github.com/slodge/MvvmCross/blob/v3/nuspec/DroidContent/SplashScreen.cs.pp
Ensure Initialize Setup before calling OnCreate.
protected override void OnCreate(Bundle bundle)
{
var setupSingleton = MvxAndroidSetupSingleton.EnsureSingletonAvailable(this);
setupSingleton.EnsureInitialized();
base.OnCreate(bundle);
}
I am designing a page in flex and I have a one image. Specific text should be shown when user hovers mouse to the image. Here is my actionScript code that I wrote but it is not working (it is not showing text on mouseOver event:(
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="100" minHeight="100">
<fx:Script>
private var helpText:String = "Some Text."
private function helpIconEvent(e:MouseEvent):void{
if(e.type == "mouseOver"){
e.currentTarget.helpText.visible = true;
}
}
private function addEventToHelpIcon():void {
helpIcon.addEventListener(MouseEvent.MOUSE_OVER, helpIconEvent);
}
</fx:Script>
<mx:Image id="helpIcon" x="270" y="187" width="50" height="50" mouseOver="addEventToHelpIcon"
source="source_path"/>
Any help/insight will be highly appreciated.
Thanks.
There are several issues:
You are not adding the mouse over listener correctly. You are actually adding two event listeners, one in MXML and then when that event happens you add the second one. Just use the MXML listener (see below).
In function that runs when the mouse over happens, you are trying to set the visible property on a String object. A String by itself will not display anything. You can display the String with a Label object, in a tool-tip, or some other GUI object. You need to figure out the right GUI object to use and pass the text to that object.
Here's a very simple example:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="100" minHeight="100">
<fx:Script>
private function onMouseOver():void {
helpLabel.visible=true;
}
private function onMouseOut():void {
helpLabel.visible=false;
}
</fx:Script>
<s:Image id="helpIcon" x="270" y="187"
width="50" height="50"
mouseOver="onMouseOver()" mouseOut="onMouseOut()"
source="source_path"/>
<!-- note the mouse event handlers are so simple in this case, you can also do them in line -->
<s:Image id="alternateMethod" mouseOver="helpLabel.visible=true;"
mouseOut="helpLabel.visible=false;" />
<s:Label id="helpLabel" x="100" y="100" visible="false" text="Some Text."/>
</s:Application>
It think your code should be more like this, but I'm not used to flex so bear with me if I'm wrong.
private function foo(e:MouseEvent):void {
if(e.type == MouseEvent.ROLL_OVER)
//Do stuff...
}