Xamarin.Android MvvmCross Data-Binding Issue - xamarin

I'm trying to create a simple app that uses the Xamarin Geofence plugin. (https://github.com/domaven/xamarin-plugins/tree/master/Geofence).
I'm using MvvmCross for model binding and the App View is interested in events coming from the Geofence instance.
On My ViewModel i have implemented the IGeofenceListener interface so that when any of the events are fired i can directly change the value of the binding properties in my ViewModel that are being targeted in the View.
public class MainViewModel : MvxViewModel, IGeofenceListener
{
double _latitude;
public double Latitude
{
get
{
return _latitude;
}
set
{
_latitude = value;
RaisePropertyChanged(() => Latitude);
}
}
double _longitude;
public double Longitude
{
get
{
return _longitude;
}
set
{
_longitude = value;
RaisePropertyChanged(() => Longitude);
}
}
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
public void OnAppStarted()
{
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Id, "App started"));
}
public void OnError(string error)
{
Debug.WriteLine(string.Format("{0} - {1}: {2}", CrossGeofence.Id, "Error", error));
}
public void OnLocationChanged(GeofenceLocation location)
{
Longitude = location.Longitude;
Latitude = location.Latitude;
Name = CrossGeofence.Id;
Debug.WriteLine(string.Format("{0} - Long: {1} || Lat: {2}", CrossGeofence.Id, location.Longitude, location.Latitude));
}
public void OnMonitoringStarted(string identifier)
{
Debug.WriteLine(string.Format("{0} - Monitoring started in region: {1}", CrossGeofence.Id, identifier));
}
public void OnMonitoringStopped()
{
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Id, "Monitoring stopped for all regions"));
}
public void OnMonitoringStopped(string identifier)
{
Debug.WriteLine(string.Format("{0} - {1}: {2}", CrossGeofence.Id, "Monitoring stopped in region", identifier));
}
public void OnRegionStateChanged(GeofenceResult result)
{
Longitude = result.Longitude;
Latitude = result.Latitude;
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Id, result.ToString()));
}
}
As you can see, On certain events Im updating the properties of my ViewModel and then calling the RaisePropertyChanged event for the View.
I've added Debug tracing to ensure that these events are actually being fired.
I can see the events firing in my Output window.. and when i debug the application i can see the properties on the ViewModel been updated. It's just that the RaisePropertyChanged event in not actually updating the View.
Here is my View Code :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00007f"
android:layout_marginTop="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
local:MvxBind="Text Longitude"
android:id="#+id/textViewLongitude"
android:textColor="#android:color/white" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
local:MvxBind="Text Latitude"
android:id="#+id/textViewLatitude"
android:textColor="#android:color/white" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
local:MvxBind="Text Name"
android:textColor="#android:color/white"
android:id="#+id/textViewName" />
</LinearLayout>
This is the App setup code in my Core Library :-
public class App : MvxApplication
{
public App()
{
Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<MainViewModel>());
}
}
Here is the Main Activity MvxClass :-
[Activity(Label = "Geofence.Android", MainLauncher = true)]
public class MainActivity : MvxActivity<MainViewModel>
{
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Main);
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
CrossGeofence.Initialize<MainViewModel>();
CrossGeofence.Current.StopMonitoring("LHR");
CrossGeofence.Current.StartMonitoring(new Plugin.Abstractions.GeofenceCircularRegion("Location", 54.9672132, -1.5992939, 2000)
{
NotifyOnStay = true,
NotifyOnEntry = true,
NotifyOnExit = true,
ShowNotification = true,
ShowEntryNotification = false,
ShowExitNotification = false,
ShowStayNotification = true,
NotificationStayMessage = "stay message!",
NotificationEntryMessage = "entry message!",
NotificationExitMessage = "exit message!",
StayedInThresholdDuration = TimeSpan.FromSeconds(1),
});
}
}

This is because CrossGeofence.Initialize<MainViewModel>(); creates a new ViewModel, that is not that one that was created by MvvmCross. You can see that, when you inspect the ViewModel of the activity in the debugger.
Solution
Use the GeofenceListener property.
CrossGeofence.GeofenceListener = (IGeofenceListener)ViewModel;
CrossGeofence.Initialize<MainViewModel>();

Related

OnTabChanged not called when click on current tab

I implemented a tabbed application with Xamarin.Android using TabHost and MvxTabsFragmentActivity.
I want to refresh the current tab when clicking on it the second time.
Is there any method like OnTabReselected from Android?
That's how I am creating the tabs, using TabHost:
<TabHost android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="7dp"
android:background="#drawable/gradient_border_top"
android:orientation="horizontal" />
<TabWidget android:id="#android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_weight="0"
android:background="#color/white" />
<FrameLayout android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</LinearLayout>
</TabHost>
And MainView:
[Activity(Theme = "#style/MyTheme", ScreenOrientation = ScreenOrientation.Portrait, WindowSoftInputMode = SoftInput.AdjustPan)]
public class MainView : MvxTabsFragmentActivity
{
public MainView() : base(Resource.Layout.main_layout, Resource.Id.actualtabcontent)
{
}
private static TabHost TabHost { get; set; }
public override void OnTabChanged(string tag)
{
var pos = TabHost.CurrentTab;
var tabView = TabHost.TabWidget.GetChildTabViewAt(pos);
tabView.FindViewById<ImageView>(Resource.Id.tabImage)
.SetColorFilter(new Color(ContextCompat.GetColor(Application.Context, Resource.Color.tabColorSelected)));
tabView.FindViewById<TextView>(Resource.Id.tabTitle)
.SetTextColor(new Color(ContextCompat.GetColor(Application.Context, Resource.Color.tabColorSelected)));
for (var i = 0; i < TabHost.TabWidget.ChildCount; i++)
{
if (pos != i)
{
var tabViewUnselected = TabHost.TabWidget.GetChildTabViewAt(i);
tabViewUnselected.FindViewById<ImageView>(Resource.Id.tabImage)
.SetColorFilter(new Color(ContextCompat.GetColor(Application.Context, Resource.Color.tabColor)));
tabViewUnselected.FindViewById<TextView>(Resource.Id.tabTitle)
.SetTextColor(new Color(ContextCompat.GetColor(Application.Context, Resource.Color.tabColor)));
}
}
base.OnTabChanged(tag);
}
}
// This is where I add all 4 tabs
protected override void AddTabs(Bundle args)
{
AddTab<TrackHomeView>(
args,
Mvx.IoCProvider.IoCConstruct<TrackHomeViewModel>(),
CreateTabFor(((int)TabIdentifier.TrackTab).ToString(), Resource.Drawable.ic_track_icon, Strings.Track));
AddTab<SendView>(
args,
Mvx.IoCProvider.IoCConstruct<SendViewModel>(),
CreateTabFor(((int)TabIdentifier.SendTab).ToString(), Resource.Drawable.ic_send_icon, Strings.Send));
if (MainViewModel.IsUserLoggedIn())
{
AddTab<ProfileView>(
args,
Mvx.IoCProvider.IoCConstruct<ProfileViewModel>(),
CreateTabFor(((int)TabIdentifier.ProfileTab).ToString(), Resource.Drawable.ic_profile_icon, Strings.Profile));
}
else
{
AddTab<CreateAccountView>(
args,
Mvx.IoCProvider.IoCConstruct<CreateAccountViewModel>(),
CreateTabFor(((int)TabIdentifier.ProfileTab).ToString(), Resource.Drawable.ic_profile_icon, Strings.Profile));
}
AddTab<MoreView>(
args,
Mvx.IoCProvider.IoCConstruct<MoreViewModel>(),
CreateTabFor(((int)TabIdentifier.MoreTab).ToString(), Resource.Drawable.ic_more_icon, Strings.More));
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
TabHost = FindViewById<TabHost>(global::Android.Resource.Id.TabHost);
TabHost.TabWidget.SetDividerDrawable(null);
TabHost.Setup();
}
I added only relevant code.
The tabs are created using TabHost, and the Activity is inherited from MvxTabsFragmentActivity.
You can inherit the ActionBar.ITabListener interface in your TabHost's MvxTabsFragmentActivity and then you can get the events that you need.
public class MainActivity : MvxTabsFragmentActivity, ActionBar.ITabListener
{
public void OnTabReselected(ActionBar.Tab tab, FragmentTransaction ft)
{
// Optionally refresh/update the displayed tab.
Log.Debug(Tag, "The tab {0} was re-selected.", tab.Text);
}
public void OnTabSelected(ActionBar.Tab tab, FragmentTransaction ft)
{
// Display the fragment the user should see
Log.Debug(Tag, "The tab {0} has been selected.", tab.Text);
}
public void OnTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
// Save any state in the displayed fragment.
Log.Debug(Tag, "The tab {0} as been unselected.", tab.Text);
}
...

Update textview in android custom notification

I have a custom local notification implementing remoteview comprising of three buttons and a textview. Button click in notification changes volume of ringer but I want to increment a variable count each time the up button click or decrement then count each time downbutton click. I have problem updating textview as the broadcaster class can't access it directly. I tried a method from a post, but I can't make it work.
I get null exception at tvUpdate.text=t;
Any idea would be appreaciated. Thanks
RemoteView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="75dp"
android:weightSum="100"
android:padding="5dp"
android:background="#969696"
android:minWidth="25px"
android:minHeight="25px">
<Button
android:text="Vol_Up"
android:layout_width="0dp"
android:layout_weight="25"
android:background="#drawable/roundcnr"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:textColor="#FFFFFF"
android:id="#+id/btnVolUp" />
<Button
android:text="V_Down"
android:layout_width="0dp"
android:layout_weight="25"
android:layout_margin="5dp"
android:textColor="#FFFFFF"
android:background="#drawable/roundcnr"
android:layout_height="wrap_content"
android:id="#+id/btnVolDown" />
<Button
android:text="Silent"
android:layout_width="0dp"
android:layout_weight="25"
android:layout_margin="5dp"
android:background="#drawable/roundcnr"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:id="#+id/btnVolSilent" />
<TextView
android:text="Status"
android:layout_width="0dp"
android:layout_weight="25"
android:textColor="#FFFFFF"
android:layout_height="wrap_content"
android:id="#+id/tvVol" />
</LinearLayout>
Broadcaster Class
namespace RingerTest
{
[BroadcastReceiver]
public class myBroadCastR : BroadcastReceiver
{
public double counter { get; set; }
public override void OnReceive(Context context, Intent intent)
{
if(intent.Action== "VolumeUp")
{
counter += 6;
// Toast.MakeText(context,"VolumeUp",ToastLength.Long).Show();
AudioManager audioManager = (AudioManager)context.GetSystemService(Context.AudioService);
audioManager.AdjustSuggestedStreamVolume(Adjust.Raise, Stream.Ring, VolumeNotificationFlags.PlaySound);
try
{
MainActivity.getinstance().updateTextView(counter.ToString() + "%");
}
catch (Exception ex)
{
}
}
else if (intent.Action == "VolumeDown")
{
counter -= 6;
// Toast.MakeText(context, "VolumeDown",ToastLength.Long).Show();
AudioManager audioManager = (AudioManager)context.GetSystemService(Context.AudioService);
audioManager.AdjustSuggestedStreamVolume(Adjust.Lower, Stream.Ring, VolumeNotificationFlags.PlaySound);
try
{
MainActivity.getinstance().updateTextView(counter.ToString() + "%");
}
catch (Exception ex)
{
}
}
else if (intent.Action == "Silent")
{
counter = 0;
// Toast.MakeText(context, "VolumeDown",ToastLength.Long).Show();
AudioManager audioManager = (AudioManager)context.GetSystemService(Context.AudioService);
audioManager.RingerMode = RingerMode.Silent;
MainActivity.getinstance().updateTextView(counter.ToString()+"%");
}
}
}
}
MainActivity
namespace RingerTest
{
[Activity(Label = "RingerTest", MainLauncher = true)]
public class MainActivity : Activity
{
public static MainActivity ins;
private myBroadCastR myBroadl;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
ins = this;
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var myreceiver = new myBroadCastR();
var intentfilter = new IntentFilter();
intentfilter.AddAction("VolumeUp");
intentfilter.AddAction("VolumeDown");
intentfilter.AddAction("Silent");
RegisterReceiver(myreceiver, intentfilter);
Button btnNotify = FindViewById<Button>(Resource.Id.button1);
btnNotify.Click += BtnNotify_Click;
}
public static MainActivity getinstance()
{
return ins;
}
public void updateTextView(string t)
{
MainActivity.ins.RunOnUiThread(() =>
{
TextView tvUpdate = FindViewById<TextView>(Resource.Id.tvVol);
tvUpdate.Text = t;
});
}
private void BtnNotify_Click(object sender, System.EventArgs e)
{
const int requestID = 1;
//Volume Up
Intent intent_V_UP = new Intent("VolumeUp");
PendingIntent pIntent_V_UP = PendingIntent.GetBroadcast(this, requestID, intent_V_UP, PendingIntentFlags.UpdateCurrent);
//Volume Down
Intent intent_V_Down = new Intent("VolumeDown");
PendingIntent pIntent_V_Down = PendingIntent.GetBroadcast(this, requestID, intent_V_Down, PendingIntentFlags.UpdateCurrent);
//Silent
Intent intent_Silent = new Intent("Silent");
PendingIntent pIntent_Silent = PendingIntent.GetBroadcast(this, requestID, intent_Silent, PendingIntentFlags.UpdateCurrent);
Notification.Builder builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.addContact);
/*
builder.SetContentTitle("VolControl");
builder.AddAction(Resource.Drawable.addContact, "VolDown", pIntent_V_Down);
builder.AddAction(Resource.Drawable.addContact, "VolUP", pIntent_V_UP);*/
//Custom View for Notification
RemoteViews remoteViews = new RemoteViews(this.PackageName, Resource.Layout.customNotification);
//On Button Click in CustomView
remoteViews.SetOnClickPendingIntent(Resource.Id.btnVolUp, pIntent_V_UP);
remoteViews.SetOnClickPendingIntent(Resource.Id.btnVolDown, pIntent_V_Down);
remoteViews.SetOnClickPendingIntent(Resource.Id.btnVolSilent, pIntent_Silent);
Notification notification = builder.Build();
notification.BigContentView = remoteViews;
notification.Flags = NotificationFlags.NoClear;
NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(1, notification);
}
}
}

How to display image with text in 2 columns GridView

How to display image with text ( like name, price.. etc )
Below code only display images with no text.
--- UI :
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="230dp"
android:numColumns="2"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:background="#ffffff"
android:stretchMode="columnWidth"
android:gravity="center" />
-- Code:
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.Views;
using Android.Widget;
namespace ModSpforce
{
class ImageAdapter : BaseAdapter
{
Context context;
public ImageAdapter(Context c)
{
context = c;
}
public override int Count
{
get { return thumbIds.Length; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public override View GetView(int position, View convertView, ViewGroup parent)
{
ImageView imageView;
if (convertView == null)
{ // if it's not recycled, initialize some attributes
imageView = new ImageView(context);
imageView.LayoutParameters = new GridView.LayoutParams(200, 200);
imageView.SetScaleType(ImageView.ScaleType.CenterCrop);
imageView.SetPadding(3, 3, 3, 3);
}
else
{
imageView = (ImageView)convertView;
}
imageView.SetImageResource(thumbIds[position]);
return imageView;
}
// references to our images
int[] thumbIds = {
Resource.Drawable.sample_2, Resource.Drawable.sample_3,
Resource.Drawable.sample_4, Resource.Drawable.sample_5,
Resource.Drawable.sample_6, Resource.Drawable.sample_7,
Resource.Drawable.sample_0, Resource.Drawable.sample_1,
Resource.Drawable.sample_2, Resource.Drawable.sample_3,
Resource.Drawable.sample_4, Resource.Drawable.sample_5,
Resource.Drawable.sample_6, Resource.Drawable.sample_7,
Resource.Drawable.sample_0, Resource.Drawable.sample_1,
Resource.Drawable.sample_2, Resource.Drawable.sample_3,
Resource.Drawable.sample_4, Resource.Drawable.sample_5,
Resource.Drawable.sample_6, Resource.Drawable.sample_7
};
}
}
You can inflate your GridView's cell in the GetView method of your adapter, so you can simply design your item's template in xml.
For example:
Code behind of your GridView:
public ObservableCollection<MyItemModel> items = new ObservableCollection<MyItemModel>();
public MyGridViewAdapter adapter;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
//add your items here.
for (int i = 0; i < 50; i++)
{
items.Add(new MyItemModel { ImageSource = Resource.Drawable.Pika, Name = "Name " + i });
}
adapter = new MyGridViewAdapter(this, items);
GridView gv = FindViewById<GridView>(Resource.Id.gridview);
gv.Adapter = adapter;
}
MyItemModel is for image resource and name of this image, like this:
public class MyItemModel
{
public string Name { get; set; }
public int ImageSource { get; set; }
}
And MyGridViewAdapter is like this:
public class MyGridViewAdapter : BaseAdapter<MyItemModel>
{
private ObservableCollection<MyItemModel> items;
private Activity context;
public MyGridViewAdapter(Activity context, ObservableCollection<MyItemModel> items)
{
this.items = items;
this.context = context;
}
public override MyItemModel this[int position]
{
get
{
return items[position];
}
}
public override int Count
{
get
{
return items.Count;
}
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
if (view == null)
{
view = context.LayoutInflater.Inflate(Resource.Layout.MyGridViewCell, null);
}
var image = view.FindViewById<ImageView>(Resource.Id.image);
image.SetImageResource(items[position].ImageSource);
var name = view.FindViewById<TextView>(Resource.Id.name);
name.Text = items[position].Name;
return view;
}
}
Finally the layout of MyGridViewCell is like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/image"
android:layout_height="200dp"
android:layout_width="200dp" />
<TextView android:id="#+id/name"
android:layout_height="wrap_content"
android:layout_width="200dp"
android:textColor="#android:color/holo_blue_light" />
</LinearLayout>

CustomFragment in MVVMCross

I have used the following template in my Android application which has navigation drawer has a list of options such as Settings.
https://github.com/MvvmCross/MvvmCross-Samples/tree/master/XPlatformMenus
Source code could be downloaded from the following url
https://github.com/MvvmCross/MvvmCross-Samples
I wonder how could I able to make Settings page as a Dialog or CustomFragment which will look like similar to following image.
One approach that you could make use of is to create a custom implementation of Dialog. Following the XPlatformMenus sample you linked to, you could implement something as follows:
Generic Custom Dialog
This class inherits android Dialog control, and can be used with any XML/AXML layout you want. You could tightly couple it to a particular ViewModel/Layout or you can make it handle a generic ViewModel type. Here is an example of the generic type:
public class CustomDialog : Dialog, IMvxBindingContextOwner
{
public CustomDialog(Context context, int layout, IMvxViewModel viewModel)
: this(context, Resource.Style.CustomDialog)
{
this.BindingContext = new MvxAndroidBindingContext(context, (context as IMvxLayoutInflaterHolder));
ViewModel = viewModel;
Init(layout);
}
public CustomDialog(Context context, int themeResId)
: base(context, themeResId)
{
}
protected CustomDialog(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected CustomDialog(Context context, bool cancelable, IDialogInterfaceOnCancelListener cancelListener)
: base(context, cancelable, cancelListener)
{
}
protected CustomDialog(Context context, bool cancelable, EventHandler cancelHandler)
: base(context, cancelable, cancelHandler)
{
}
private void Init(int layout)
{
SetContentView(layout);
}
public override void SetContentView(int layoutResID)
{
var view = this.BindingInflate(layoutResID, null);
base.SetContentView(view);
}
public IMvxBindingContext BindingContext { get; set; }
public object DataContext
{
get { return this.BindingContext.DataContext; }
set { this.BindingContext.DataContext = value; }
}
public IMvxViewModel ViewModel
{
get { return this.DataContext as IMvxViewModel; }
set { this.DataContext = value; }
}
}
XML layout for modal:
<?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout 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="wrap_content"
android:background="#color/colorPrimary">
<Button
android:id="#+id/btn_option"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show"
local:MvxBind="Click ShowSettingsCommand"/>
<Button
android:id="#+id/btn_close"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/btn_option"
android:text="CLOSE"
local:MvxBind="Click ShowCloseCommand"/>
</RelativeLayout>
CustomDialog style:
<resources>
<style name="CustomDialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
Custom Presenter
Create a custom presenter to handle the navigation to show/hide the dialog:
public class CustomPresenter : MvxFragmentsPresenter
{
protected IMvxViewModelLoader MvxViewModelLoader => Mvx.Resolve<IMvxViewModelLoader>();
CustomDialog _modal;
public CustomPresenter(IEnumerable<Assembly> AndroidViewAssemblies) : base(AndroidViewAssemblies)
{
}
protected override void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null)
{
if (!Intercept(request))
base.ShowActivity(request, fragmentRequest);
}
protected override void ShowFragment(MvxViewModelRequest request)
{
if (!Intercept(request))
base.ShowFragment(request);
}
private bool Intercept(MvxViewModelRequest request)
{
if (request.ViewModelType == typeof(ThirdViewModel))
{
var activity = Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
var viewModel = MvxViewModelLoader.LoadViewModel(request, null) as ThirdViewModel;
_modal = new CustomDialog(activity, Resource.Layout.modal_popup, viewModel);
_modal.Show();
return true;
}
if (_modal != null)
{
_modal.Dismiss();
_modal = null;
}
return false;
}
}
Register your custom presenter in the setup class:
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
var mvxFragmentsPresenter = new CustomPresenter(AndroidViewAssemblies);
Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxFragmentsPresenter);
return mvxFragmentsPresenter;
}
ViewModel
public class ThirdViewModel : BaseViewModel
{
private MvxCommand _showSettingsCommand;
public MvxCommand ShowSettingsCommand =>
_showSettingsCommand ?? (_showSettingsCommand = new MvxCommand(() => ShowViewModel<HomeViewModel>()));
private MvxCommand _showCloseCommand;
public MvxCommand ShowCloseCommand =>
_showCloseCommand ?? (_showCloseCommand = new MvxCommand(() => ShowViewModel<SettingsViewModel>()));
}

How to make a Single Row Horizontal ListView/List?

What I want to do is Create a Single Row Listview/List with a image and text is this is what i have right now
I have Changed the numColumns to 1 but how do I change it so it is Horizontal and Scrollable? the image should be one top and the text should be below it?
This is the Layout
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="1"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
Single Grid Item
<?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="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:id="#+id/my_image_vieww" />
<TextView
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/my_text_view" />
</LinearLayout>
Main Activity
var gridview = FindViewById<GridView> (Resource.Id.gridview);
gridview.Adapter = new ImageAdapter (this);
gridview.ItemClick += delegate (object sender, AdapterView.ItemClickEventArgs args) {
Toast.MakeText (this, args.Position.ToString (), ToastLength.Short).Show ();
};
public class ImageAdapter : BaseAdapter
{
Context context;
public ImageAdapter (Context c)
{
context = c;
}
public override int Count {
get { return thumbIds.Length; }
}
public override Java.Lang.Object GetItem (int position)
{
return null;
}
public override long GetItemId (int position)
{
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public override View GetView (int position, View convertView, ViewGroup parent)
{
ImageView imageView;
View view;
if (convertView == null) { // if it's not recycled, initialize some attributes
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.my_grid_row, parent, false);
} else {
view = convertView;
}
var imageView2 = view.FindViewById<ImageView>(Resource.Id.my_image_vieww);
imageView2.SetImageResource (thumbIds[position]);
var textView = view.FindViewById<TextView>(Resource.Id.my_text_view);
textView.Text = "Text to Display";
return view;
}
}
Please Dont user horizontal list view.
There is predefined android controll to achieve this. View Pager
Sample Code:
var _viewPager = view.FindViewById<ViewPager>(Resource.Id.viewPager);
var _viewPageIndicatorCircle = view.FindViewById<CirclePageIndicator>(Resource.Id.viewPageIndicator);
_viewPager.Adapter = new TestFragmentAdapter(fm);
_viewPageIndicatorCircle.SetViewPager(_viewPager);
public class TestFragmentAdapter : FragmentPagerAdapter
{
public TestFragmentAdapter(Android.Support.V4.App.FragmentManager fm)
: base(fm)
{
}
public override Android.Support.V4.App.Fragment GetItem(int position)
{
return new TestFragment();
}
public override int Count
{
get
{
return 5;
}
}
}
class TestFragment : Android.Support.V4.App.Fragment
{
public TestFragment()
{
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = inflater.Inflate(Resource.Layout.MyViewPager , container, false);
return view;
}
}
Viewpager.xml
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="209.6dp" />
If you have any queries please feel free to ask me

Resources