How can you set AnimateLayoutChanges to True via C# in Xamarin.Android? - c#

How can you set AnimateLayoutChanges to True via C# in Xamarin.Android for a linear layout? I cannot use an xml resource file when building this custom view. The xml for this linear layout would be this:
<LinearLayout
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:id="#+id/linearLayoutOne"
android:layout_weight="1"/>
All of the other attributes can be set via C# via the following:
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent, 1);
linearLayoutOne = new LinearLayout(Context);
linearLayoutOne.Orientation = Orientation.Vertical;
linearLayoutOne.LayoutParameters = layoutParams;
linearLayoutOne.SetMinimumHeight(25);
linearLayoutOne.SetMinimumWidth(25);
So how in the world do you set AnimateLayoutChanges in C#?

The C# equivalent of setting that is:
linearLayoutOne.LayoutTransition = new LayoutTransition();
linearLayoutOne.LayoutTransition.EnableTransitionType(LayoutTransitionType.Changing);

Related

recycle view not rendering and displaying data from firebase when run on physical device but works fine on emulator

I am trying to build a native android app in xamarin where users can sign in and upload post to the feed page and also view posts from other users on their feed. The feed page has a recycler view which renders posts from the firebase and also has an upload option for users to upload posts to firebase, which then will be retrieved back to the app and be displayed in the feed page. everything works fine on the emulator (user sign-in->user view feeds->user upload posts etc). But when I build the release file and install it on my android 10 phone, only the sign in functionality works which uses validation from firebase. The feeds recycler view does not work anymore and does not display posts from firebase, and also every time a user tries to upload a posts to firebase, the app crashes, shows the splash screen, and then finally exits. I have looked up everywhere for an answer but could not find any so I decided to seek help here. Below are some code snippets:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/drawerLayout"
android:fitsSystemWindows="true"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/include_main"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navview"
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#color/white"
android:layout_gravity="start"
app:headerLayout="#layout/navheader"
app:menu="#menu/navmenu"
/>
</androidx.drawerlayout.widget.DrawerLayout>
include_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:theme="#style/AppTheme.ToolBarOverlay"
app:popupTheme="#style/AppTheme.PopupOverlay"
android:id="#+id/toolbar"
android:background="#color/colorPrimary"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize">
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<ImageView
android:id="#+id/userIcon"
android:src="#drawable/account"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_marginRight="15sp"
android:layout_centerVertical="true"/>
<TextView
android:text="Feed"
android:textSize="20sp"
android:textColor="#color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textStyle="bold"/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="65dp"
android:background="#color/white"
android:clickable="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:id="#+id/layStatus"
android:elevation="4dp">
<RelativeLayout
android:layout_width="240dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:background="#drawable/roundedges">
<TextView
android:text="What's on your mind?"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center"
android:layout_centerInParent="true"/>
</RelativeLayout>
<ImageView
android:id="#+id/userIcon"
android:src="#drawable/add"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/>
<ImageView
android:src="#drawable/photo"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/postRecycleView"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scrollbars="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="16dp"
/>
</LinearLayout>
MainActivity.cs
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.App;
using AndroidX.RecyclerView.Widget;
using System;
using System.Collections.Generic;
using TransGlobal.Adapter;
using TransGlobal.DataModels;
using TransGlobal.Activities;
using TransGlobal.Actvities;
using TransGlobal.EventListeners;
using System.Linq;
using TransGlobal.Helpers;
using Firebase.Storage;
using TransGlobal.Fragments;
using Android.Content;
namespace TransGlobal
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = false)]
public class MainActivity : AppCompatActivity
{
AndroidX.AppCompat.Widget.Toolbar toolbar;
RecyclerView postRecyclerView;
PostAdapter postAdapter;
List<Post> ListOfPost;
RelativeLayout layStatus;
//ImageView cameraImage;
AndroidX.DrawerLayout.Widget.DrawerLayout drawerLayout;
Google.Android.Material.Navigation.NavigationView navigationView;
PostEventListener postEventListener;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
toolbar = (AndroidX.AppCompat.Widget.Toolbar)FindViewById(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
drawerLayout = (AndroidX.DrawerLayout.Widget.DrawerLayout)FindViewById(Resource.Id.drawerLayout);
navigationView = (Google.Android.Material.Navigation.NavigationView)FindViewById(Resource.Id.navview);
navigationView.NavigationItemSelected += NavigationView_NavigationItemSelected;
//this block of code is new since git upload
AndroidX.AppCompat.App.ActionBar actionBar = SupportActionBar;
actionBar.SetHomeAsUpIndicator(Resource.Drawable.menuaction);
actionBar.SetDisplayHomeAsUpEnabled(true);
postRecyclerView = (RecyclerView)FindViewById(Resource.Id.postRecycleView);
layStatus = (RelativeLayout)FindViewById(Resource.Id.layStatus);
layStatus.Click += LayStatus_Click;
//cameraImage = (ImageView)FindViewById(Resource.Id.camera);
//cameraImage.Click += LayStatus_Click;
// Retreives fullname on Login
FullnameListener fullnameListener = new FullnameListener();
fullnameListener.FetchUser();
// CreateData();
FetchPost();
}
private void NavigationView_NavigationItemSelected(object sender, Google.Android.Material.Navigation.NavigationView.NavigationItemSelectedEventArgs e)
{
if (e.MenuItem.ItemId == Resource.Id.navFunds)
{
Intent intent = new Intent(this, typeof(FundsActivity));
// intent.PutExtra("topic", "History");
StartActivity(intent);
drawerLayout.CloseDrawers();
}
else if (e.MenuItem.ItemId == Resource.Id.navHealth)
{
Intent intent = new Intent(this, typeof(HealthActivity));
// intent.PutExtra("topic", "History");
StartActivity(intent);
drawerLayout.CloseDrawers();
}
else if (e.MenuItem.ItemId == Resource.Id.navProfile)
{
Intent intent = new Intent(this, typeof(ProfileActivity));
intent.PutExtra("topic", "History");
StartActivity(intent);
drawerLayout.CloseDrawers();
}
else if (e.MenuItem.ItemId == Resource.Id.navLogout)
{
postEventListener.RemoveListener();
AppDataHelper.GetFirebaseAuth().SignOut();
StartActivity(typeof(LoginActivity));
Finish();
drawerLayout.CloseDrawers();
}
}
private void LayStatus_Click(object sender, EventArgs e)
{
StartActivity(typeof(CreatePostActivity));
}
void FetchPost()
{
postEventListener = new PostEventListener();
postEventListener.FetchPost();
postEventListener.OnPostRetrieved += PostEventListener_OnPostRetrieved;
}
private void PostEventListener_OnPostRetrieved(object sender, PostEventListener.PostEventArgs e)
{
ListOfPost = new List<Post>();
ListOfPost = e.Posts;
if (ListOfPost != null)
{
ListOfPost = ListOfPost.OrderByDescending(x => x.PostDate).ToList();
}
SetupRecyclerView();
}
void CreateData()
{
ListOfPost = new List<Post>();
ListOfPost.Add(new Post { PostBody = "The United States has been lobbying for months to prevent its western allies from using Huawei equipment in their 5G deployment, and on Wednesday, Washington made it more difficult for the Chinese telecom ", Author = "Uchenna Nnodim", LikeCount = 12 });
ListOfPost.Add(new Post { PostBody = "TE Connectivity is a technology company that designs and manufactures connectivity and sensor products for harsh environments in a variety of industries, such as automotive, industrial equipment, ", Author = "Johan Gasierel", LikeCount = 34 });
ListOfPost.Add(new Post { PostBody = "Singapore-based startup YouTrip thinks consumers of Southeast Asia deserve a taste of the challenger bank revolution happening in the U.S. and Europe, and it has raised $25 million in new funding to bring its app-and-debit-card service to more parts in the region.", Author = "Kylie Jenna", LikeCount = 6 });
ListOfPost.Add(new Post { PostBody = "TE Connectivity is a technology company that designs and manufactures connectivity and sensor products for harsh environments in a variety of industries, such as automotive, industrial equipment, ", Author = "Johan Gasierel", LikeCount = 78 });
}
void SetupRecyclerView()
{
postRecyclerView.SetLayoutManager(new AndroidX.RecyclerView.Widget.LinearLayoutManager(postRecyclerView.Context));
postAdapter = new PostAdapter(ListOfPost);
postRecyclerView.SetAdapter(postAdapter);
postAdapter.ItemLongClick += PostAdapter_ItemLongClick;
postAdapter.LikeClick += PostAdapter_LikeClick;
}
private void PostAdapter_LikeClick(object sender, PostAdapterClickEventArgs e)
{
Post post = ListOfPost[e.Position];
LikeEventListener likeEventListener = new LikeEventListener(post.ID);
if (!post.Liked)
{
likeEventListener.LikePost();
}
else
{
likeEventListener.UnlikePost();
}
}
private void PostAdapter_ItemLongClick(object sender, PostAdapterClickEventArgs e)
{
string postID = ListOfPost[e.Position].ID;
string ownerID = ListOfPost[e.Position].OwnerId;
if (AppDataHelper.GetFirebaseAuth().CurrentUser.Uid == ownerID)
{
AndroidX.AppCompat.App.AlertDialog.Builder alert = new AndroidX.AppCompat.App.AlertDialog.Builder(this);
alert.SetTitle("Edit or Delete Post");
alert.SetMessage("Are you sure");
// Edit Post on Firestore
alert.SetNegativeButton("Edit Post", (o, args) =>
{
EditPostFragment editPostFragment = new EditPostFragment(ListOfPost[e.Position]);
var trans = SupportFragmentManager.BeginTransaction();
editPostFragment.Show(trans, "edit");
});
// Delete Post from Firestore and Storage
alert.SetPositiveButton("Delete", (o, args) =>
{
AppDataHelper.GetFirestore().Collection("posts").Document(postID).Delete();
StorageReference storageReference = FirebaseStorage.Instance.GetReference("postImages/" + postID);
storageReference.Delete();
});
alert.Show();
}
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
drawerLayout.OpenDrawer((int)GravityFlags.Left);
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
}
}
If you need anymore code snippets of a particular class or xml, you can add a comment stating so. I will be more than happy to provide as much code snippets as I can or even provide you with the full source code. Your help will be highly appreciated.

Xamarin Android TabLayout Badge: Bind Text Mvvmcross

I made a Custom Layout to add a badge to a tab on Android. This badge is a TextView.
How do I bind this component?
It's possible?
My custom badge layout:
<LinearLayout
android:id="#+id/badgeCotainer"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="90dp"
android:background="#drawable/notifications_background"
android:gravity="center"
android:layout_gravity="right"
android:minWidth="16dp">
<TextView
android:id="#+id/badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="#011f7a"
android:textSize="10sp"
android:text="0"
app:MvxBind="Text ContMaterial"/>
</LinearLayout>
My Activity: use MvxViewPagerFragmentInfo
private void InitTabs()
{
var viewPager = FindViewById<ViewPager>(Resource.Id.materiais_viewpager);
if (viewPager != null)
{
var fragments = new List<MvxViewPagerFragmentInfo>
{
new MvxViewPagerFragmentInfo("Requisição",
typeof(CadastraRequisicaoFragment), ViewModel),
new MvxViewPagerFragmentInfo("Materiais",
typeof(ListaMateriaisFragment), ViewModel),
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(this, SupportFragmentManager, fragments);
}
var tabLayout = FindViewById<TabLayout>(Resource.Id.requisicao_tabs);
tabLayout.SetupWithViewPager(viewPager);
tabLayout.GetTabAt(1).SetCustomView(Resource.Layout.tab_header_badge);
}
On view Model I used raisedPropertyChanged()
Badge appears normally, just don't change value.
Tablayout
Out of the box there is nothing in mvvmcross to bind the content of a TabLayout when you provide a custom view. You could however try something custom using MvxFrameControl
Basically, replace your LinearLayout by the MvxFrameControl, then after
tabLayout.SetupWithViewPager(viewPager);
inflate your custom view using the BindingInflate method, and set a value to your MvxFrameControl's BindingContext, then set your custom tablayout view with the result that operation.
That might do the trick.
Another way to do it, is to listen to your ViewModel's "PropertyChanged" events in your Activity, and manually make changes to your tab layouts when it applies.

Add icons to TabLayout using MvvmCross

I've been looking at the Playground project on MvvmCross (https://github.com/MvvmCross/MvvmCross/tree/develop/Projects/Playground)
The way to have a fragment loaded into the tabs is to set the attribute the following way:
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", ActivityHostViewModelType = typeof(TabsRootViewModel))]
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", FragmentHostViewType = typeof(TabsRootBView))]
[Register(nameof(Tab1View))]
public class Tab1View : MvxFragment<Tab1ViewModel>
My questions is, besides the title that can be specified on the MvxTabLayoutPresentation, how can I add and icon to each one of the tabs?
That is not provided out-of-the-box and it's more about TabLayout customization.
You can achieve it like this.
Create a CustomView for your tab layout item, myCustomTab.axml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/txtTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#FFFFFF"
android:textSize="12"
android:textStyle="bold" />
Then in your view that has the TabLayout you configure it on the OnCreate / OnCreateView:
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
var customTab = inflater.Inflate(Resource.Layout.myCustomTab, null);
customTab.Text = "MyText";
// this sets the icon above the text
customTab.SetCompoundDrawablesWithIntrinsicBounds(0, Resource.Drawable.my_icon, 0, 0);
tabLayout.GetTabAt(0).SetCustomView(customTab);
Obviously you have to do this as many times as tab layout items you have.
Furthermore using this you can add any customization to your tab layout items.
Source (in java): https://mobikul.com/make-custom-tabs-icons-android/
HIH

Replacing a fragment - New instance of fragment class isn't instantiated

I'm trying to replace a fragment with a another fragment with the following lines of code:
FragmentTransaction ft = Activity.FragmentManager.BeginTransaction();
UploadCompleted ucompleted = new UploadCompleted();
ft.Replace(Resource.Id.CameraFragmentContainer, ucompleted, "uploadcompleted");
ft.AddToBackStack(null);
ft.Commit();
The fragment is being replaced inside another fragment which uses the Activity's fragment manager. The issue is that the OnCreate and OnCreateView methods of the replaced fragment aren't invoked and an old instance of fragment (the fragment which was instantiated the first time I replaced it) get's instantiated which is why I'm not able to pass any new values to the replaced fragment. Any idea what I'm doing wrong? I'm new to android development so my knowledge of fragments isn't that great.
As per your logic, OnCreate and OnCreateView of the new Fragment should get invoked. It is a good practice to do FragmentTransaction at Activity level rather than, at Fragment level. In the above snippet you are creating an instance of the new Fragment from within the already displayed Fragment and replacing itself from the parent Activity. This is not a recommended approach. I would suggest the following change.
public class ParentActivity:Activity
{
public void ChangeToUploadCompleted()
{
FragmentTransaction ft = FragmentManager.BeginTransaction();
UploadCompleted ucompleted = new UploadCompleted();
ft.Replace(Resource.Id.CameraFragmentContainer, ucompleted, "uploadcompleted");
ft.AddToBackStack(null);
ft.Commit();
}
}
public FirstFragment:Fragment
{
void CaptureCompleted ()
{
((ParentActivity)Activity).ChangeToUploadCompleted();
}
}
This is the good practice to switch fragments. This might fix your problem too
ft.Replace(Resource.Id.CameraFragmentContainer, ucompleted, "uploadcompleted");
In this R.id is the layout that you place in Fragment Activity or Activity and UploadCompleted is Fragment class which you want to replace so use xml like this in FRagmentActivity or ACtivity class
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/lin"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</LinearLayout>
when you want to replace use this
FragmentTransaction ft = Activity.FragmentManager.BeginTransaction();
UploadCompleted ucompleted = new UploadCompleted();
ft.Replace(Resource.Id.lin, ucompleted, "uploadcompleted");
ft.AddToBackStack(null);
ft.Commit();

How to hyperlink TextView in C# android?

I would like to display a some text that when clicked will redirect me to a website. I am writing by android app with C# (Xamarian studio).
<TextView
android:id="#+id/rsstitle"
android:autoLink="web"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="16dip"
android:textStyle="bold" />
view.FindViewById<TextView> (Resource.Id.rsstitle).Text = values [position];
//values[position] contains a title string eg "Google"
links[position] contains a uri eg "https://www.google.co.nz/"
How do I make it so that "Google" is displayed but when clicked directs to https://www.google.co.nz/
Found my solution:
String linkText = "" + values [position] + " ";
link.TextFormatted = Html.FromHtml(linkText);
link.MovementMethod = LinkMovementMethod.Instance;

Categories