Implementing NavDrawer on android - c#

I'm about to implement NavDrawer on android using Mvvmcross and Xamarin (in c#), but I'm a bit worried about having my HomeView model look like this: https://github.com/jamesmontemagno/Xam.NavDrawer/blob/master/Mvx/MvxSample/ViewModels/HomeViewModel.cs.
How would I use a view model like that on a MS platform, where I would probably have a panarama or something very different to layout the data.
Should I perhaps have a separate home viewmodel for platforms that don't support a NavDrawer type experience?

Navigation Bar implementation for api level > 7
NavDrawerProject/res/values/strings.xml
<resources>
<string-array name="pages_array">
<item>Home</item>
<item>Trending</item>
<item>Profile</item>
</string-array>
<resources>
NavDrawerProject/res/layout/activity_main.xml
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#color/drawer_bg"
android:paddingTop="?attr/actionBarSize"/>
</android.support.v4.widget.DrawerLayout>
NavDrawerProject/src/MainActivity.java
public class MainActivity extends ActionBarActivity {
// navigation drawer
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPageTitles;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setting up navigation drawer
mTitle = mDrawerTitle = getTitle();
mPageTitles = getResources().getStringArray(R.array.pages_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPageTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
// TODO find out if stray {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
// TODO find out if stray
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content
// view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
}
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
}
private void selectItem(int position) {
// update the main content by replacing fragments
Fragment fragment;
switch (position) {
case 0:
fragment = new HomePageFragment();
break;
case 1:
fragment = new TrendingPageFragment();
break;
case 2:
fragment = new ProfilePageFragment();
break;
default:
fragment = new HomePageFragment();
break;
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_main, fragment);
transaction.addToBackStack(null);
transaction.commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPageTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
}

To use Navigation Drawer on old Android, you should take a look at Support Library.
http://components.xamarin.com/view/xamandroidsupportv7appcompat

Related

How do I register an arrow click handler in the navigation page?

I have two navigation pages, one root page, and a second page that can be accessed from the first.
I have no desire to prescribe a separate button for this when there is an arrow at the top.
Is it possible to somehow register a Clicked event handler for it yourself?
From what you are asking, I believe you are trying to have an event handler that can intercept navigation events.
Xamarin.Forms Shell has a Navigating event you can subscribe to that allows you to see the current navigation, where it intends to navigate to, and allows you to cancel navigation or redirect. This captures all navigation, so it isn't just the back button, but will also capture moving forward as well.
Here is an example of navigation being intercepted in a ContentPage:
public class ExampleContentPage : ContentPage
{
public ExampleContentPage()
{
Content = new StackLayout
{
Children = {
new Label { Text = "Welcome to Xamarin.Forms!" }
}
};
}
protected override void OnAppearing()
{
base.OnAppearing();
// subscribe to event listener on appearing
Shell.Current.Navigating += Current_Navigating;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// remove event listener on disappearing
Shell.Current.Navigating -= Current_Navigating;
}
private async void Current_Navigating(object sender, ShellNavigatingEventArgs e)
{
if (sender is Shell shell)
{
// cancels navigation so we can do what we need
if (e.CanCancel)
{
e.Cancel();
}
// continue navigation to it's original target if we so choose
Shell.Current.Navigating -= Current_Navigating;
await Shell.Current.GoToAsync(e.Target, true);
}
}
}
However; if you're looking to override the functionality of the arrow button, I think you need to define the Shell's BackButtonBehavior.
This can be done either through XAML or C#. I've attached Microsoft's examples here:
<ContentPage ...>
<Shell.BackButtonBehavior>
<BackButtonBehavior Command="{Binding BackCommand}"
IconOverride="back.png" />
</Shell.BackButtonBehavior>
...
</ContentPage>
Shell.SetBackButtonBehavior(this, new BackButtonBehavior
{
Command = new Command(() =>
{
...
}),
IconOverride = "back.png"
});
And here is the documentation for overriding the back button behavior: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#back-button-behavior
To handle the backbutton event on android, you can override the OnOptionsItemSelected and OnBackPressed method in mainactivity, like:
public override void OnBackPressed()
{
// this is not necessary, but in Android user
// has both Nav bar back button and
// physical back button its safe
// to cover the both events
// retrieve the current xamarin forms page instance
var currentpage = (BackArrowTest)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
// check if the page has subscribed to
// the custom back button event
if (currentpage?.CustomBackButtonAction != null)
{
currentpage?.CustomBackButtonAction.Invoke();
}
else
{
base.OnBackPressed();
}
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
// check if the current item id
// is equals to the back button id
if (item.ItemId == 16908332)
{
// retrieve the current xamarin forms page instance
var currentpage = (BackArrowTest)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
// check if the page has subscribed to
// the custom back button event
if (currentpage?.CustomBackButtonAction != null)
{
// invoke the Custom back button action
currentpage?.CustomBackButtonAction.Invoke();
// and disable the default back button action
return false;
}
// if its not subscribed then go ahead
// with the default back button action
return base.OnOptionsItemSelected(item);
}
else
{
// since its not the back button
//click, pass the event to the base
return base.OnOptionsItemSelected(item);
}
}
Then you can create a page which has EnableBackButtonOverrideProperty and your custom event like:
public class BackArrowTest : ContentPage
{
public Action CustomBackButtonAction { get; set; }
public static readonly BindableProperty EnableBackButtonOverrideProperty =
BindableProperty.Create(
nameof(EnableBackButtonOverride),
typeof(bool),
typeof(BackArrowTest),
false);
public bool EnableBackButtonOverride
{
get
{
return (bool)GetValue(EnableBackButtonOverrideProperty);
}
set
{
SetValue(EnableBackButtonOverrideProperty, value);
}
}}
At last you can set the event:
<bk:BackArrowTest xmlns:bk="clr-namespace:MyForms2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
EnableBackButtonOverride="True"
x:Class="MyForms2.MyPage1"
>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</bk:BackArrowTest>
codebehind:
public partial class MyPage1 : BackArrowTest
{
public MyPage1()
{
InitializeComponent();
this.EnableBackButtonOverride = true;
this.CustomBackButtonAction = () => { Console.WriteLine("Do something"); };
}
}
FYI:don't forget to set the Actionbarsupport in mainactivity like:
AndroidX.AppCompat.Widget.Toolbar toolbar = this.FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);

NavigationView SetCheckedItem does not trigger OnNavigationItemSelected

I want to select a specific item in nav drawer when application starts.
I added navigationView.SetCheckedItem(Resource.Id.nav_gallery); in visual studio default template.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
FloatingActionButton fab = FindViewById<FloatingActionButton>(Resource.Id.fab);
fab.Click += FabOnClick;
DrawerLayout drawer = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, Resource.String.navigation_drawer_open, Resource.String.navigation_drawer_close);
drawer.AddDrawerListener(toggle);
toggle.SyncState();
var navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
navigationView.SetNavigationItemSelectedListener(this);
navigationView.SetCheckedItem(Resource.Id.nav_gallery);
}
But OnNavigationItemSelected is not called
public bool OnNavigationItemSelected(IMenuItem item)
{
int id = item.ItemId;
if (id == Resource.Id.nav_camera)
{
// Handle the camera action
}
else if (id == Resource.Id.nav_gallery)
{
}
If I click the nav items OnNavigationItemSelected is called and everything works right.
What is the proper way to select a default item?
UPDATE
I solved it adding this line. The specific item gets clicked.
navigationView.Menu.PerformIdentifierAction(Resource.Id.nav_gallery, 0);
navigationView.getMenu().getItem(position).setChecked(true);
you can create a function
public void selectDrawerItem(int position, String tag) {
switch (position) {
case 0:
fragment = new DashboardFragment();
tvToolbarTitleLand.setText("Dashboard");
break;
//code.................
}
if (fragment != null) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_right);
transaction.replace(R.id.flMainContainer, fragment);
transaction.addToBackStack(tag);
transaction.commit();
}
navigationView.getMenu().getItem(position).setChecked(true);
}
let me know if you have any queries about this.
select that item programmatically
public class BaseApp extends AppCompatActivity {
//define variables
protected String LOGTAG = "LOGDEBUG";
protected Toolbar toolbar;
protected NavigationView navigationView;
protected DrawerLayout drawerLayout;
private DateManager db = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
navigationView = (NavigationView) findViewById(R.id.navigation_view);
// set the dashboard at startup
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame, new DashboardFragment());
fragmentTransaction.commit();
setNavDrawer();
}
//CREATE A NavDrawer() void
private void set NavDrawer(){
toolbar = (toolbar) findViewById(r.i.d.toolbar);
setsupportactionbar(toolbar);
navigationView.setNavigationItemSelected(memuItem)
{
if (menuItems.isChecked()) menuItem.setChecked(false);
else menuItem.setChecked(true);
drawerlayout.closeDrawers();
//now checlk which items are being clicked
//and performing appropriate action
if (menuItem.isChecked()) menuItem.setChecked(false);
else menuItem.setChecked(true);
switch (menuItem.getItemId()) {
case R.id.home:
DashboardFragment dashboardFragment = new DashboardFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame, dashboardFragment,"DASHBOARD_FRAGMENT");
fragmentTransaction.commit();
return true;

XAMARIN: How to Link [Android] Hardware Back Button to Webkit.WebView?

I'm trying to link the hardware back button into my WebViews in Xamarin for Android. My WebViews are contained within OnCreate instances of TabHost (which is deprecated, but I'm using it anyway) I've got this inside my MainActivity : TabActivity class
public override void OnBackPressed()
{
base.OnBackPressed();
}
and here's an example of one of my Tab Activity Classes
[Activity]
public class SpeakersActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
//set the content view
SetContentView(Resource.Layout.subs);
//declare webview and tell our code where to find the XAML resource
WebView subWebView = FindViewById<WebView>(Resource.Id.webViewSubs);
//set the webview client
subWebView.SetWebViewClient(new WebViewClient());
//load the subscription url
subWebView.LoadUrl("https://www.bitchute.com/subscriptions/");
//enable javascript in our webview
subWebView.Settings.JavaScriptEnabled = true;
//zoom control on? This should perhaps be disabled for consistency?
//we will leave it on for now
subWebView.Settings.BuiltInZoomControls = true;
subWebView.Settings.SetSupportZoom(true);
//scrollbarsdisabled
// subWebView.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
subWebView.ScrollbarFadingEnabled = false;
}
}
and I've seen a lot information how to use this
subWebView.GoBack();
to goback in a webview, but the problem is that my WebViews are not within the scope of my hardware back button. The hardware back button is inside mainactivity class and my webviews are inside individual instances of the tab activities.
What's the best way to correct this issue? Thank you!
Thanks so much #SushiHangover !!!
I solved it like this:
[Activity]
public class SpeakersActivity : Activity
{
public override void OnBackPressed()
{
WebView subWebView = FindViewById<WebView>(Resource.Id.webViewSubs);
subWebView.GoBack();
}
}
EDIT: the way you do this with a ViewPager and Fragment is as follows:
//put this code in your MainActivity.cs
public override bool OnKeyDown(Android.Views.Keycode keyCode, KeyEvent e)
{
if (e.KeyCode == Android.Views.Keycode.Back)
{
switch (_viewPager.CurrentItem)
{
case 0:
_fm1.WebViewGoBack();
break;
case 1:
_fm2.WebViewGoBack();
break;
case 2:
_fm3.WebViewGoBack();
break;
case 3:
_fm4.WebViewGoBack();
break;
case 4:
_fm5.WebViewGoBack();
break;
}
}
return false;
}
then in a fragment instantiate WebView assign in OnCreate and create a method for going back inside Fragment :
protected static WebView _wv;
protected static View _view;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
_view = inflater.Inflate(Resource.Layout.TheFragmentLayout1, container, false);
_wv = _view.FindViewById<WebView>(Resource.Id.webView1);
//lots of code
}
public void WebViewGoBack()
{
if (_wv.CanGoBack())
_wv.GoBack();
}

How to find the parent class of a particular object in Android C#?

I'm currently having an issue where views in a RecycleView are being disposed, despite the Dispose function of the RecyclerView not being called (checked by setting variable) nor it being recycled (also checked by setting a variable).
The main issue: MvxPropertyChangedListener not being cleared. The listener then tries to perform an operation on the disposed view, causing an issue. No matter where I call listener.Clear() (from onViewRecycled in the RecycleView.Adapter, from Dispose, before we initially bind the ViewModel), I still get 'object is disposed' exception.
A try-catch around the view in question 'fixes' the issue, but doesn't solve the root problem.
Question:
In Xamarin, how do I track these RecycleViews? Through my try-catch, I can see which ones have the issue (which is why I can track whether it's disposed, recycled etc.) and the associated ViewModel, but do not then know how to track why and where these inner view objects are disposed?
Note: I have more experience with iOS dev. My Android understanding is fair but lacking atm.
Edit: Code provided.
public class CarouselViewHolder : BaseCarouselViewHolder
{
private SimpleProgressBar _progressBar;
// tile listener
private MvxPropertyChangedListener _tileListener;
private CarouselTileViewModel Tile => (Item as CarouselTileViewModel);
public SingleCarouselItemViewHolder(View v) : base(v)
{
_progressBar = v.FindViewById<BasicProgressBar>(Resource.Id.progressBar);
}
public override void PrepareForReuse()
{
ClearTileListener();
base.PrepareForReuse();
}
public void SetTile(CarouselTileViewModel tile)
{
// keep the item
Item = tile;
// progress bar
RefreshProgressBar ();
// listeners
SetupTileListener();
}
private void SetupTileListener()
{
ClearTileListener();
// setup the listener for the item
if(Item != null && Item is CarouselTileViewModel)
{
_tileListener = new MvxPropertyChangedListener(Item as CarouselTileViewModel);
_tileListener.Listen (() => (Item as CarouselTileViewModel).Progress, RefreshProgressBar);
}
}
private void RefreshProgressBar ()
{
try
{
if (_progressBar != null)
{
_progressBar.Visibility = Tile.Progress > 0 ? ViewStates.Visible : ViewStates.Gone;
_progressBar.SetProgress(Tile.Progress);
}
}
catch (ObjectDisposedException e)
{
Phx.TaggedError ("BasicProgressBar already disposed", "Exception {0}", e);
}
}
private void ClearTileListener()
{
// kill any old listeners
if(_tileListener != null)
{
_tileListener.Clear();
_tileListener.Dispose();
_tileListener = null;
}
}
public override void OnAttachedToWindow()
{
}
public override void OnDetachedFromWindow()
{
}
protected override void Dispose(bool disposing)
{
ClearTileListener();
base.Dispose(disposing);
}
}
public class CarouselItemAdapter : BaseCarouselAdapter<CarouselViewModel>
{
.
.
.
public override void OnViewAttachedToWindow(Java.Lang.Object holder)
{
base.OnViewAttachedToWindow(holder);
if(holder is CarouselViewHolder)
{
(holder as CarouselViewHolder).OnAttachedToWindow();
}
}
public override void OnViewDetachedFromWindow(Java.Lang.Object holder)
{
base.OnViewDetachedFromWindow(holder);
if (holder is CarouselViewHolder)
{
(holder as CarouselViewHolder).PrepareForReuse();
(holder as CarouselViewHolder).OnDetachedFromWindow();
}
}
public override void OnViewRecycled(Java.Lang.Object holder)
{
base.OnViewRecycled(holder);
if (holder is CarouselViewHolder)
{
(holder as CarouselViewHolder).PrepareForReuse();
}
}
}
With MvvmCross you shouldn't have to worry about writing your own ViewHolder or Adapter classes. The MvxRecyclerView takes care of implementing these classes and binds all of the ViewModels.
Define an MvxRecyclerView in your parent view:
<MvxRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
local:MvxBind="ItemClick TileClickedCommand; ItemsSource Tiles;"
local:MvxItemTemplate="#layout/tileitemview" />
Note the MvxItemTemplate, this is where you specify a secondary view to use for each of your TileViewModels.
Your child view can look as simple as something like this:
<TextView 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"
local:MvxBind="Text Format('{0:f}', Progress)" />
Note: I used a TextView to only represent how a child view will bind to a child ViewModel. The child view can contain any number of controls as you want.

send email by clicking textview in customized listview with android Xamarin

I am facing errors trying to send email by clicking a textview field inside a listview with Xamarin, all related to the instance of the activity not being avaiable to call the email Intent.
I´ve tried different approaches, but no success at all.
first I´ve tried to call a method inside the activity clas (i´ve used a method for that in adapter, but it did not work);
so I´ve changed to try call the textview click event. In java it seems easily done with the expression :
if (mContext instanceof MyActivity) { methodCall() };
In C#, I've tried to use
if (mContext.GetType() == TypeOf(ListaVereadoresActivity))
but this does not work,
And also, the presented solution in code below, trying to call the StartActivity(email);
ERROR: Unhandled Exception:
Java.Lang.Exception: No Activity found to handle Intent {
act=android.intent.action.SEND typ=message/rfc822 flg=0x10000000 (has
extras) }
CODE SAMPLES:
[Activity(Label = "Vereadores")]
public class ListaVereadoresActivity : Activity
{
List<Vereador> listaVer = new List<Vereador>();
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.listaVereadores_layout);
GenerateListaVereadores();
ListView vereadorListView = FindViewById<ListView>(Resource.Id.lstVereadores2);
vereadorListView.ItemClick += OnListItemClick;
VereadorAdapter adapter = new VereadorAdapter(this, listaVer, this.ApplicationContext);
vereadorListView.Adapter = adapter;
}
// not using anymore
public void SendEmail(String emailAdd)
{
var email = new Intent(Android.Content.Intent.ActionSend);
email.SetType("message/rfc822");
email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { emailAdd });
StartActivity(email);
}
private void GenerateListaVereadores()
{
var azuaite = new Vereador();
azuaite.Nome = "Azuaite";
azuaite.Foto = Resource.Drawable.azuaite;
azuaite.Email = "some#email.address";
listaVer.Add(azuaite);
var aleksander = new Vereador();
aleksander.Nome = "Aleksander";
aleksander.Foto = Resource.Drawable.aleksander;
aleksander.Email = "some#email.address";
listaVer.Add(aleksander);
var dhony = new Vereador();
dhony.Nome = "dhony";
dhony.Foto = Resource.Drawable.dhony;
dhony.Email = "other#email.address";
listaVer.Add(dhony);
}
void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
var listView = sender as ListView;
var t = listaVer[e.Position];
Toast.MakeText(this, t.Nome, ToastLength.Short).Show();
}
my custom adapter:
public class VereadorAdapter : BaseAdapter
{
private List<Vereador> vereadorList;
Activity activity;
protected Context mContext;
public VereadorAdapter(Activity act, List<Vereador> v, Context appContext)
{
activity = act;
vereadorList = v;
mContext = appContext;
}
public override int Count
{
get { return vereadorList.Count; }
}
class ViewHolder : Java.Lang.Object
{
public TextView nomeVereadorTxt { get; set; }
public TextView emailVereadorTxt { get; set; }
public ImageView fotoVereadorImg { get; set; }
}
public override Java.Lang.Object GetItem(int position)
{
var vereador = (Vereador)vereadorList[position];
return vereador;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = vereadorList[position];
ViewHolder holder;
var view = convertView;
if (view != null)
{
holder = view.Tag as ViewHolder;
}
else
{
holder = new ViewHolder();
view = activity.LayoutInflater.Inflate(Resource.Layout.CustomView, parent, false);
holder.nomeVereadorTxt = view.FindViewById<TextView>(Resource.Id.VereadorNome);
holder.fotoVereadorImg = view.FindViewById<ImageView>(Resource.Id.VereadorFoto);
holder.emailVereadorTxt = view.FindViewById<TextView>(Resource.Id.VereadorEmail);
view.Tag = holder;
}
//setar as propriedades dos componentes
holder.emailVereadorTxt.Text = item.Nome;
holder.fotoVereadorImg.SetImageResource(item.Foto);
holder.emailVereadorTxt.Text = item.Email;
holder.emailVereadorTxt.Click += EmailVereadorTxt_Click;
return view;
}
private void EmailVereadorTxt_Click(object sender, EventArgs e)
{
TextView tv = (sender as TextView);
string mailAddress = tv.Text;
Toast.MakeText(activity.BaseContext, mailAddress, ToastLength.Short).Show();
var email = new Intent(Android.Content.Intent.ActionSend);
email.AddFlags(ActivityFlags.NewTask);
email.SetType("message/rfc822");
email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { mailAddress });
Application.Context.ApplicationContext.StartActivity(email);
}
}
here my custom view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="#drawable/CustomSelector">
<ImageView
android:id="#+id/VereadorFoto"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:src="#drawable/Icon" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/VereadorNome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:paddingTop="5dp" />
<TextView
android:id="#+id/VereadorEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:paddingTop="5dp" />
</LinearLayout>
</LinearLayout>
So, how is the right way to implement an send email action by clicking the email text?
I think you might be misinterpreting the error you're getting.
When you try and start an activity on Android you send an intent, and the operating system tries to respond to that intent in the best way it can. If you set up the intent to have a specific activity subclass in mind, then it will open your activity subclass. However, if you set up the intent to have something more generic like an action, you leave it to the operating system's interpretation. Normally, this means it will try and find activities that have registered themselves as being able to handle that action intent.
In this case, you are starting an activity with ACTION_SEND and the operating system is throwing an error because it can't find any activities that have registered themselves as being able to handle ACTION_SEND. Normally this means that the device (or emulator) you're running on doesn't have an email app installed.
If you want to check with the operating system first to see if it can find an activity for an intent, you should use resolveActivity(intent) which will return null if it cannot find one.
Hope this helps.

Categories

Resources