How to make a viewpager inside a Listview - c#

I have a Listview and in it are 4 different kinds of views. One of them should be a ViewPager (like in the playstore). Using a PagerAdapter I have put the Viewpager in the Listview with 3 pictures. But I can't get it as smooth as the PlayStore.
Has anyone tried this before and succeeded in this?
My Getview in the adapter looks like this:
public override View GetView(int position, View convertView, ViewGroup parent)
{
int type = position;
if (convertView == null) {
switch (type) {
case 0:
convertView = inflater.Inflate (Resource.Layout.DetailHeader, null);
TextView tv = convertView.FindViewById<TextView> (Resource.Id.Title);
tv.Text = Info.title;
ImageView iv = convertView.FindViewById<ImageView> (Resource.Id.iconImage);
iv.SetImageDrawable (Info.icon);
Button Button = convertView.FindViewById<Button> (Resource.Id.Button);
installButton.Text = "";
installButton.Click += delegate {
confirm ();
};
break;
case 1:
convertView = inflater.Inflate (Resource.Layout.DetailScroller, null);
ImageViewPager adapter = new ImageViewPager (context, appInfo.shots);
ViewPager myPager = convertView.FindViewById<ViewPager> (Resource.Id.imagepager);
myPager.Adapter = adapter;
myPager.SetCurrentItem (0, true);
break;
case 2:
convertView = inflater.Inflate (Resource.Layout.DetailInfo, null);
TextView infoView = convertView.FindViewById<TextView> (Resource.Id.textView);
infoView.Text = "Information";
break;
case 3:
convertView = inflater.Inflate (Resource.Layout.DetailInfo, null);
TextView descView = convertView.FindViewById<TextView> (Resource.Id.textView);
descView.Text = "Description";
break;
}
}
}
ImageViewPager:
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;
using Android.Support.V4.View;
namespace EnterpriseAppstore
{
class ImageViewPager : PagerAdapter
{
Activity activity;
Android.Graphics.Drawables.BitmapDrawable[] imageArray;
public ImageViewPager(Activity act, Android.Graphics.Drawables.BitmapDrawable[] imgArray) {
imageArray = imgArray;
activity = act;
}
public override int Count {
get {
return imageArray.Length;
}
}
public override Java.Lang.Object InstantiateItem (View p0, int p1)
{
ImageView view = new ImageView(activity);
view.LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
view.SetScaleType(ImageView.ScaleType.FitXy);
view.SetImageDrawable(imageArray[p1]);
((ViewPager) p0).AddView(view, 0);
return view;
}
public override bool IsViewFromObject (View p0, Java.Lang.Object p1)
{
return p0 == ((View) p1);
}
public override void DestroyItem (View p0, int p1, Java.Lang.Object p2)
{
((ViewPager) p0).RemoveView((View) p2);
}
}
}

Related

Xamarin, New activity on itemClick in RecyclerView

I'm trying to make Master and Details Application for learning purpose.
In my recyclerview, When I click item I want to start new activity and send data to a new activity.
I was making it in listview examples, but I struggled here.
This is my Adapter
using Android.App;
using Android.Widget;
using Android.OS;
using System.Threading.Tasks;
using System;
using System.Threading;
using System.Collections.Generic;
using Android.Content;
using Newtonsoft.Json;
using Petrolium.DataObjects;
using Petrolium.Utilities;
using Petrolium.Activities;
using Android.Support.V7.Widget;
using Android.Views;
using static Android.Support.V7.Widget.RecyclerView;
namespace Petrolium.Adapters
{
public class CompanyRecyclerAdapter : RecyclerView.Adapter
{
static List<Company> _companies = new List<Company>();
public CompanyRecyclerAdapter(Context context, List<Company> companies) => _companies = companies;
public override int ItemCount => _companies.Count;
private class CompanyViewHolder : ViewHolder
{
public ImageView companyImageView
{
get;
set;
}
public TextView companyNameView
{
get;
set;
}
public CompanyViewHolder(View itemView) : base(itemView)
{
companyImageView = itemView.FindViewById<ImageView>(Resource.Id.company_image);
companyNameView = itemView.FindViewById<TextView>(Resource.Id.company_name);
itemView.Click += (sender, e) =>
{
var context = itemView.Context;
Intent intent = new Intent(context, typeof(DetailsActivity));
intent.PutExtra(GetText(Resource.String.DetailsStringToJSON),
JsonConvert.SerializeObject(_companies[e.Position].Fuels));
StartActivity(intent);
};
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
CompanyViewHolder vh = holder as CompanyViewHolder;
vh.companyImageView.SetImageResource(Resource.Drawable.gulf);
vh.companyNameView.Text = _companies[position].Name;
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemview = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.Company, parent, false);
CompanyViewHolder vh = new CompanyViewHolder(itemview);
return vh;
}
}
}
But there isn't GetText method, also e. doesn't have any Position field or property.
Also, there isn't StartActivity method to pass my intent on it.
What is best-practice to make itemClick in recyclerView and start a new activity? How to handle this problem?
I'm the beginner in android development and sorry if I'm asking something simple.
Your ViewHolder should be just pass out the click event to the Adapter then back to the Fragment or Activity to handle the event.
public CompanyViewHolder(View itemView, Action<int> listener) : base(itemView)
{
companyImageView = itemView.FindViewById<ImageView>(Resource.Id.company_image);
companyNameView = itemView.FindViewById<TextView>(Resource.Id.company_name);
itemView.Click += (sender, e) => listener (base.LayoutPosition);
}
Then in your adapter should have an event to let Fragment or Activity to bind to:
public class CompanyRecyclerAdapter : RecyclerView.Adapter
{
public event EventHandler<int> ItemClick;
void OnClick(int position)
{
if (ItemClick != null)
ItemClick(this, position);
}
...
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemview = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.Company, parent, false);
CompanyViewHolder vh = new CompanyViewHolder(itemview, OnClick);
return vh;
}
}
Then finally in your Fragment or Activity you can bind to the ItemClick event in Adapter to handle it:
mAdapter = new CompanyRecyclerAdapter(mPhotoAlbum);
mAdapter.ItemClick += OnItemClick;

How do I update a ListView?

Hi guys I have a problem. I have a DialogFragment with content that is saved in a sqlite db on the phone, and a Fragment that retrieves the information and shows it. The ListView initially (upon creation) shows everything like its supposed to, but when the stuff is updated inside the Dialog Fragment, I dont know how to update the adapter for ListView. Here is my 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.Util;
using Android.Views;
using Android.Widget;
namespace Zrelya.Fragments
{
public class OnSelectedEventArgs : EventArgs
{
public ORM.Plan Plan { get; set; }
public OnSelectedEventArgs( ORM.Plan plan )
{
Plan = plan;
}
}
public class ViewPlans : FragmentSuper
{
private Context mContext;
private ORM.DBRep dbr;
public EventHandler<OnSelectedEventArgs> OnSelected;
public ViewPlans(Context context)
{
mContext = context;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
dbr = new ORM.DBRep();
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
var view = inflater.Inflate(Resource.Layout.ViewPlans, container, false);
var listView = view.FindViewById<ListView>(Resource.Id.listView);
List<ORM.Plan> plansList = dbr.GetPlans();
Adapters.Plan adapter = new Adapters.Plan(mContext, plansList);
listView.Adapter = adapter;
listView.ItemClick += (o, e) =>
{
int id = plansList[e.Position].Id;
OnSelected.Invoke(this, new OnSelectedEventArgs(plansList[e.Position]));
};
return view;
}
}
}
OnSelected.Invoke is what happens when an item is clicked, showing the dialog fragment. The following code is a snippet from MainActivity OnCreate method:
fragmentViewPlans.OnSelected += (o, e) =>
{
int id = e.Plan.Id;
DialogViewPlan(e.Plan);
};
...and the DialogViewPlan method is below:
private void DialogViewPlan(ORM.Plan plan)
{
if (plan != null)
{
Android.App.FragmentTransaction transaction = FragmentManager.BeginTransaction();
Helpers.DialogViewPlan dialog = new Helpers.DialogViewPlan(this, plan);
dialog.Show(transaction, "dialog");
dialog.OnDelete += delegate
{
Toast.MakeText(this, "Plan deleted...", ToastLength.Short).Show();
};
dialog.OnSave += delegate
{
Toast.MakeText(this, "Plan saved!", ToastLength.Short).Show();
};
}
}
I dont know how to talk between activity, fragment and dialog fragment, does anyone know how to do this?
I found an answer:
using Android.App;
using Android.Content;
using Android.OS;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
namespace Zrelya.Fragments
{
public class OnSelectedEventArgs : EventArgs
{
public ORM.Plan Plan { get; set; }
public OnSelectedEventArgs( ORM.Plan plan )
{
Plan = plan;
}
}
public class ViewPlans : FragmentSuper
{
private Context mContext;
private ORM.DBRep dbr;
private static Adapters.Plan Adapter;
private static ListView listView;
public EventHandler<OnSelectedEventArgs> OnSelected;
public ViewPlans(Context context)
{
mContext = context;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
dbr = new ORM.DBRep();
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
var view = inflater.Inflate(Resource.Layout.ViewPlans, container, false);
listView = view.FindViewById<ListView>(Resource.Id.listView);
List<ORM.Plan> plansList = dbr.GetPlans();
Adapter = new Adapters.Plan(mContext, plansList);
listView.Adapter = Adapter;
listView.ItemClick += (o, e) =>
{
int id = plansList[e.Position].Id;
var plan = plansList[e.Position];
DialogViewPlan(plan);
};
return view;
}
private void DialogViewPlan(ORM.Plan plan)
{
if (plan != null)
{
FragmentTransaction transaction = Activity.FragmentManager.BeginTransaction();
Helpers.DialogViewPlan dialog = new Helpers.DialogViewPlan(Activity, plan);
dialog.Show(transaction, "dialog");
dialog.OnDelete += delegate
{
Adapter = new Adapters.Plan(mContext, dbr.GetPlans());
listView.Adapter = Adapter;
};
dialog.OnSave += delegate
{
Adapter = new Adapters.Plan(mContext, dbr.GetPlans());
listView.Adapter = Adapter;
};
}
}
}
}

call NotifyDataSetChanged inside a nested class in my adapter

I have a listview with a button in it. if i click this button the row it is in needs to be deleted. it "kinda" works, the only thing that is giving me issues is that it does not refresh good. only if i go out and back in the list its gone. or if i flip my screen.
this is the code i have at the moment.
using System;
using System.Collections.Generic;
using Android.App;
using Android.Graphics;
using Android.Views;
using Android.Widget;
using CardAppReal.Lib.Models;
using NavigationDrawerTest;
using Square.Picasso;
using SQLite;
using Path = System.IO.Path;
namespace CardAppReal.Assets
{
public class ListAdapter : BaseAdapter<Card>
{
List<Card> items;
Activity context;
public ListAdapter(Activity context, List<Card> items)
: base()
{
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override Card this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(NavigationDrawerTest.Resource.Layout.CardSavedRowLayout, null);
view.FindViewById<TextView>(NavigationDrawerTest.Resource.Id.TextCardSavedList1).Text = item.name;
view.FindViewById<TextView>(NavigationDrawerTest.Resource.Id.TextCardSavedList2).Text = item.supertype;
view.FindViewById<TextView>(NavigationDrawerTest.Resource.Id.TextCardSavedList3).Text = item.set;
Picasso.With(context).Load(item.imageUrl).Into(view.FindViewById<ImageView>(NavigationDrawerTest.Resource.Id.CardSavedImage));
var imgButton = view.FindViewById<ImageButton>(NavigationDrawerTest.Resource.Id.ImgButtonSaved);
Picasso.With(context).Load(Resource.Drawable.delete).Into(imgButton);
view.SetBackgroundColor(Color.Argb(150, 153, 217, 234));
imgButton.Tag = item.id;
imgButton.SetOnClickListener(new ButtonClickListener(this.context, this));
return view;
}
private class ButtonClickListener : Java.Lang.Object, View.IOnClickListener
{
private Activity activity;
private ListAdapter adapter;
public ButtonClickListener(Activity activity, ListAdapter adapter)
{
this.activity = activity;
this.adapter = adapter;
}
public void OnClick(View v)
{
string name = (string)v.Tag;
string text = $"{name} Button Click.";
Toast.MakeText(this.activity, text, ToastLength.Short).Show();
string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),
"database.db3");
var db = new SQLiteConnection(folder);
db.Delete<Card>(v.Tag.ToString());
adapter.NotifyDataSetChanged();
}
}
}
}
i tried giving the adapter to the listener but that does not really work.

How can I get Google Glass gestures working with Xamarin?

I'm using Xamarin to build a Google Glass application, and haven't been able to get the GestureDetector to fire any OnGesture events. Here is what I've tried so far:
In my Activity:
using Gesture = Android.Glass.Touchpad.Gesture;
using GestureDetector = Android.Glass.Touchpad.GestureDetector;
private GestureDetector _gestureDetector;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
this._gestureDetector = new GestureDetector(this);
this._gestureDetector.SetBaseListener(new GestureListener());
}
public override bool OnGenericMotionEvent(MotionEvent e)
{
if (this._gestureDetector != null)
{
return this._gestureDetector.OnMotionEvent(e);
}
return false;
}
The IBaseListener implementation:
class GestureListener : GestureDetector.IBaseListener
{
public bool OnGesture(Gesture gesture)
{
if (gesture == Gesture.SwipeRight)
{
// do something on right (forward) swipe
return true;
}
else if (gesture == Gesture.SwipeLeft)
{
// do something on left (backwards) swipe
return true;
}
return false;
}
public void Dispose()
{
}
public IntPtr Handle { get; set; }
}
I tried setting a breakpoint just inside the OnGesture method, but it is never triggered. Is there something missing from my IBaseListener implementation?
It turns out that I needed to make my listener implementation extend Java.Lang.Object, as mentioned in the Xamarin article about Android Callable Wrappers. Below is a fully working sample Activity.
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Gesture = Android.Glass.Touchpad.Gesture;
using GestureDetector = Android.Glass.Touchpad.GestureDetector;
namespace GlassGestureTest
{
using Android.Util;
using Java.Util.Logging;
[Activity(Label = "GlassGestureTest", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
private GestureDetector _gestureDetector;
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
this._gestureDetector = new GestureDetector(this);
this._gestureDetector.SetBaseListener(new GestureListener());
}
public override bool OnGenericMotionEvent(MotionEvent e)
{
if (this._gestureDetector != null)
{
return this._gestureDetector.OnMotionEvent(e);
}
return false;
}
}
// Note - the key part here is to extend Java.Lang.Object in order to properly setup
// the IntPtr field and Dispose method required by IBaseListener
public class GestureListener : Java.Lang.Object, GestureDetector.IBaseListener
{
public bool OnGesture(Gesture gesture)
{
if (gesture == Gesture.SwipeRight)
{
// do something on right (forward) swipe
return true;
}
else if (gesture == Gesture.SwipeLeft)
{
// do something on left (backwards) swipe
return true;
}
else if (gesture == Gesture.SwipeDown)
{
// do something on the down swipe
return true;
}
else if (gesture == Gesture.SwipeUp)
{
// do something on the up swipe
return true;
}
return false;
}
}
}

first time programming app for android using monoDevelop (C#) cant understand bug

Error CS0508: 'my_android_project.ImageAdapter.GetItem(int)': return type must be 'Java.Lang.Object' to match overridden member 'Android.Widget.BaseAdapter.GetItem(int)
Here is my first class:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace my_android_project
{
[Activity (Label = "my_android_project", MainLauncher = true)]
public class Activity1 : Activity
{
int count = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
var gridview = FindViewById<GridView> (Resource.Id.gridview);
gridview.ItemClick += delegate(object sender, ItemEventArgs args) {
Toast.MakeText (this, EventArgs.Postion.ToString () , ToastLength.Short).Show();
};
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate {
button.Text = string.Format ("{0} clicks!", count++); };
}
}
}
Second Class:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace my_android_project
{
// base class is ImageAdapter , derived class is BaseAdapter
/// <summary>
/// class start
/// </summary>
public class ImageAdapter : BaseAdapter
{
private readonly Context context;
public ImageAdapter(Context c)
{
context = c;
}
public override int Count
{
get { return thumbIds.Length; }
}
public override Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
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 AbsListView.LayoutParams(85, 85);
imageView.SetScaleType(ImageView.ScaleType.CenterCrop);
imageView.SetPadding(8, 8, 8, 8);
}
else
{
imageView = (ImageView) convertView;
}
imageView.SetImageResource(thumbIds[position]);
return imageView;
} // end of GetView
private readonly 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
}; // end of thumbIds array
} // end of class
} // end of namespace
looks like on line 32 of my 2nd class Mono Develop does not like that 'null' return ..
any ideas? Im in process of learning C# and a bit more comfortable with it that android app dev :)
The issue is actually your second GetItem() method. The base class defines an abstract object getItem(int position) (per http://developer.android.com/reference/android/widget/BaseAdapter.html) so your second method isn't overriding anything.

Categories

Resources