My problem is that I require the first pages of my app to be Native. I need a way to Navigate from a Xamarin Forms Content Page to the first native pages of the app when a user signs out. Is there anyway of from a Forms page starting a native ViewController (iOS) or starting an Activity (Android). I use custom renderers regularly.
It would be brilliant if I could somehow restart the app or call AppDelegate again or something.
Any help is appreciated.
If you use custom renderers regularly, then you can create a custom view renderer like this. For example:
In PCL:
public class NewView : View
{
}
In Android platform, create a layout under /Resources/layout first like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="#+id/tv"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="this is new view." />
<Button android:id="#+id/btn"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="change text" />
</LinearLayout>
Then create the renderer for NewView like this:
public class NewViewRenderer : ViewRenderer
{
private TextView tv;
private Android.Widget.Button btn;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var context = Xamarin.Forms.Forms.Context;
LayoutInflater minflater = context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
var view = minflater.Inflate(Resource.Layout.newview, this, false);
tv = view.FindViewById<TextView>(Resource.Id.tv);
btn = view.FindViewById<Android.Widget.Button>(Resource.Id.btn);
SetNativeControl(view);
}
if (e.OldElement != null)
{
btn.Click -= Btn_Click;
}
if (e.NewElement != null)
{
btn.Click += Btn_Click;
}
}
private void Btn_Click(object sender, EventArgs e)
{
tv.Text = "Text changed!";
}
}
Finally use this view in ContentPage to make it like a page:
<ContentPage.Content>
<local:NewView />
</ContentPage.Content>
For iOS platform, there should be a method to set the ViewController as native control for a view renderer. But I'm not familiar with iOS, you may give a try.
Related
i need to display a video in mobile app which was developed in Xamarin(Andriod) in which the for forward it moving 15 sec ahead and for backward it is moving 5 sec back
Can i get some help on this
In your case you seems to use the MediaController . However , if you want to custom the length of forward and back , you need to create a custom MediaController .
in 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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main"
android:orientation="vertical">
<VideoView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/videoView1" />
<LinearLayout
android:background="#android:color/darker_gray"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:text="back"
android:id="#+id/back"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<Button
android:text="play"
android:id="#+id/play"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<Button
android:text="forward"
android:id="#+id/forward"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
in Activity
VideoView videoView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
//...
videoView = FindViewById<VideoView>(Resource.Id.videoView1);
videoView.SetVideoURI(Android.Net.Uri.Parse("xxx.mp4")); // Path of your saved video file.
videoView.Start();
Button back = FindViewById<Button>(Resource.Id.back);
back.Click += Back_Click;
Button play = FindViewById<Button>(Resource.Id.play);
play.Click += Play_Click;
Button forward = FindViewById<Button>(Resource.Id.forward);
forward.Click += Forward_Click; ;
}
private void Forward_Click(object sender, EventArgs e)
{
videoView.SeekTo(videoView.CurrentPosition + 5 * 1000);
}
private void Play_Click(object sender, EventArgs e)
{
var button = sender as Button;
if (videoView.IsPlaying)
{
button.Text = "Play";
videoView.Pause();
}
else
{
button.Text = "Pause";
videoView.Start();
}
}
private void Back_Click(object sender, EventArgs e)
{
videoView.SeekTo(videoView.CurrentPosition-15*1000);
}
And in this way you just need to set the icon of the Buttons as you want .
I got a simple layout with TabLayout and PageViewer but can't get them to work together
<com.google.android.material.tabs.TabLayout
android:id="#+id/sliding_tabs_emoji"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:tabMode="scrollable"
app:tabGravity="fill"
app:tabIndicatorColor="#color/gray"
app:tabIndicatorHeight="1dp"
android:paddingBottom="2dp"/>
<androidx.viewpager.widget.ViewPager
android:id="#+id/viewpager_emoji"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/red"/>
In my Activity OnCreate initializing the following
//Fragment array
var fragments = new AndroidX.Fragment.App.Fragment[]
{
Library.Fun.Emoji.Fragments.Recent.NewInstance(),
Library.Fun.Emoji.Fragments.People.NewInstance(),
};
//Tab title array
var titles = Android.Runtime.CharSequence.ArrayFromStringArray(new[] {
"Recent" ,
"People"
});
var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager_emoji);
//viewpager holding fragment array and tab title text
viewPager.Adapter = new EmojiTabsPagerAdapter(SupportFragmentManager, fragments, titles);
// Give the TabLayout the ViewPager
TAB_Layout.SetupWithViewPager(viewPager);
Toast.MakeText(this, "SET", ToastLength.Short);
TAB_Layout.GetTabAt(0).SetIcon(Resource.Drawable.ic_camera);
TAB_Layout.GetTabAt(1).SetIcon(Resource.Drawable.ic_camera);
Where the Adapter is simple as it could be as following
public class EmojiTabsPagerAdapter : FragmentPagerAdapter
{
private readonly AndroidX.Fragment.App.Fragment[] fragments;
private readonly ICharSequence[] titles;
public EmojiTabsPagerAdapter(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment[] fragments, ICharSequence[] titles) : base(fm)
{
this.fragments = fragments;
this.titles = titles;
}
public override int Count
{
get
{
return fragments.Length;
}
}
public override AndroidX.Fragment.App.Fragment GetItem(int position)
{
return fragments[position];
}
public override ICharSequence GetPageTitleFormatted(int position)
{
//return titles[position];
return null;
}
}
Tabs are appearing but Fragments are not loading, The results are the following
Where it should load RECENT and PEOPLE fragments on each tab, my Fragment XML is the following
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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:layout_width="match_parent"
android:layout_height="300dp"
android:background="#color/green">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="RECENTS"/>
</RelativeLayout>
And fragment's code is the following (for RECENT)
public class Recent : AndroidX.Fragment.App.Fragment
{
public static Recent NewInstance()
{
var frag = new Recent { Arguments = new Bundle() };
return frag;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate(Resource.Layout.fragment_emoji_recent, container, false);
return view;
}
}
Any Idea what am I doing wrong?
I use two Fragments: TabFragment1, TabFragment2 to test. In your code, you did provide the code about SetupWithViewPager.
The code below works well for me.
void setupViewPager(Android.Support.V4.View.ViewPager viewPager)
{
var adapter = new Adapter(SupportFragmentManager);
adapter.AddFragment(new TabFragment1(), "First Fragment");
adapter.AddFragment(new TabFragment2(), "Second Fragment");
viewPager.Adapter = adapter;
viewpager.Adapter.NotifyDataSetChanged();
//viewpager.OffscreenPageLimit(4);
}
In MainActivity, you could set like below.
var tabLayout = FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewpager);
You could download the source file from the link: https://www.c-sharpcorner.com/article/xamarin-android-create-viewpager-tablayout-floatingactionbutton-supportacti/
Did this work before moving to AndroidX?
I think you may need to pass ChildFragmentManager instead of FragmentManager to your PagerAdapter.
I have 3 EditText:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusedByDefault="false"
android:minWidth="25px"
android:minHeight="25px"
android:id="#+id/editText1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusedByDefault="true"
android:clickable="false"
android:id="#+id/editText2" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusedByDefault="false"
android:id="#+id/editText3" />
I want when the activity is opened the second EditText to be focused(with the cursor blinking in it) but when I tap on it I don't want the keyboard to show up.
Here's an example I put together that works for me. And with this solution, you can remove the "focusedByDefault" and "clickable" attributes from all of your EditText views in your layout file.
public class MainActivity : AppCompatActivity, View.IOnTouchListener {
private EditText editText2;
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.main);
editText2 = FindViewById<EditText>(Resource.Id.editText2);
editText2.RequestFocus();
editText2.SetOnTouchListener(this); // Requires addition of View.IOnTouchListener interface to class
}
public bool OnTouch(View v, MotionEvent e) {
v.OnTouchEvent(e);
var imm = (Android.Views.InputMethods.InputMethodManager)v.Context.GetSystemService(InputMethodService);
imm?.HideSoftInputFromWindow(v.WindowToken, Android.Views.InputMethods.HideSoftInputFlags.None);
return true;
}
}
This is the main activity where I am setting all the icons, menu, drawer and my navigation view. Here I set another view by inflating nav_header into the view and set the textview but I still can't seem to change the textview in the navigation drawer.
MainActivity
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Support.V4.Widget;
using Android.Views;
using RoutineApp.Fragments;
using Android.Support.V7.App;
using Android.Support.V4.View;
using Android.Support.Design.Widget;
using Android.Widget;
using Android.Content;
namespace RoutineApp
{
[Activity(Label = "#string/app_name", MainLauncher = true, LaunchMode = LaunchMode.SingleTop)]
public class MainActivity : AppCompatActivity
{
DrawerLayout drawerLayout;
NavigationView navigationView;
IMenuItem previousItem;
TextView UserNameTxt;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.main);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
SetSupportActionBar(toolbar);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
}
drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
SupportActionBar.SetHomeAsUpIndicator(Resource.Drawable.ic_menu);
navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.nav_header, null);
UserNameTxt = view.FindViewById<TextView>(Resource.Id.UserNameTxt);
UserNameTxt.Text = "Yousuf";
navigationView.NavigationItemSelected += (sender, e) =>
{
if (previousItem != null)
previousItem.SetChecked(false);
navigationView.SetCheckedItem(e.MenuItem.ItemId);
previousItem = e.MenuItem;
switch (e.MenuItem.ItemId)
{
case Resource.Id.nav_home_1:
ListItemClicked(0);
break;
case Resource.Id.nav_home_2:
ListItemClicked(1);
break;
}
drawerLayout.CloseDrawers();
};
if (savedInstanceState == null)
{
navigationView.SetCheckedItem(Resource.Id.nav_home_1);
ListItemClicked(0);
}
}
int oldPosition = -1;
private void ListItemClicked(int position)
{
if (position == oldPosition)
return;
oldPosition = position;
Fragment fragment = null;
switch (position)
{
case 0:
fragment = Fragment1.NewInstance();
break;
}
FragmentTransaction fragmentTx = this.FragmentManager.BeginTransaction();
fragmentTx.Replace(Resource.Id.content_frame, fragment);
fragmentTx.AddToBackStack(null);
fragmentTx.Commit();
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
drawerLayout.OpenDrawer(GravityCompat.Start);
return true;
}
return base.OnOptionsItemSelected(item);
}
}
}
This is the main layout axml where the navigation and drawer are set the header is called in the navigation.
main.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- The main content view -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/toolbar_layout" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/nav_menu" />
</android.support.v4.widget.DrawerLayout>
This is my the nav_header which I have called in the navigation view, which contains the textview which I'm trying to change on main activity.
nav_header.axml
<TextView
android:id="#+id/UserNameTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Username"
android:textAppearance="#style/TextAppearance.AppCompat.Body1" />
</LinearLayout>
The name doesn't change, please help.
You use LayoutInflator to inflate a view from nav_header, which means you created a total new View from nav_header.xml and changed it's sub textview's text and didn't use this new view in your activity. Thus the text of your original activity won't change.
solution:
Modify your activity codes like this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.main);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
SetSupportActionBar(toolbar);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
}
drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout); SupportActionBar.SetHomeAsUpIndicator(Resource.Drawable.ic_menu);
navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
//LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
//View view = inflater.Inflate(Resource.Layout.nav_header, null);
//UserNameTxt = view.FindViewById<TextView>(Resource.Id.UserNameTxt);
//UserNameTxt.Text = "Yousuf";
LinearLayout header=(LinearLayout)navigationView.GetHeaderView(0);
UserNameTxt = header.FindViewById<TextView>(Resource.Id.UserNameTxt);
UserNameTxt.Text = "Yousuf";
...
I'm guessing this is easy, but can't seem to nail it.
I want to define a button in an axml file, and link the click up to a handler. I know that I can manually set the handler using FindViewById<Button>(Resource.Id.Button2).Click += buttonClick;, however I'm wondering if that's necessary.
How do I have the handler bound by merit of android:onClick="buttonClick" in the axml file? The error thrown is
Could not find a method buttonClick(View) in the activity class md....Activity1 for onClick handler on view class android.widget.Button with id 'Button1'
[Activity (Label = "SlidingMenuExample", MainLauncher = true)]
public class Activity1 : Activity
{
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
SetContentView (Resource.Layout.menu);
}
public void buttonClick(object sender, EventArgs e) {
}
// This seems similar to the Java approaches. Why doesn't it work?
//public void buttonClick(View view) {
//}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="#+id/Button2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="button 2"
android:onClick="buttonClick" />
</LinearLayout>
Thanks.
Sure you can do that. You need to add a reference to Mono.Android.Export.
Then you need to annotate your method like:
[Export("buttonClick")]
private void ButtonClick(View view)
{
}
If you don't annotate the method, the Java world won't know of your method in the Activity.