Mono For Android, FindViewById A CheckBoxPreference? - c#

I have a PreferenceScreen, where the user can check/uncheck a checkbox.
To get access any Control in the Activity I used always:
var button = FindViewById<Button>(Resource.Id.myButton);
Well now, I want to access my CheckBoxPreference..
, but its not working and I get this Exception:
The type 'Android.Preferences.CheckBoxPreference' cannot be used as type parameter 'T' in the generic type or method 'Android.App.Activity.FindViewById(int)'. There is no implicit reference conversion from 'Android.Preferences.CheckBoxPreference' to 'Android.Views.View'.
How my PreferenceScreen.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="Basic"
android:id="#+id/preferenceCategory">
<CheckBoxPreference
android:id="#+id/preferenceCheckBox"
android:key="usetestdata"
android:title="Testdata ON/OFF"
android:defaultValue="true" />
</PreferenceCategory>
</PreferenceScreen>
and the not working code:
var aCheckBox = FindViewById<CheckBoxPreference>(Resource.Id.preferenceCheckBox);
aCheckBox.Enabled = false;
Maybe someone can help me and tell me on how to access controls within an activity from a PreferenceScreen?

Here is the code for using PreferenceActivity
public class SettingsActivity extends PreferenceActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add the prefernces.xml layout
addPreferencesFromResource(R.xml.preferences);
final CheckBoxPreference cf = (CheckBoxPreference) findPreference("checkbox"));
cf.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
// do something here
return false;
}
});
}
your preferences.xml in xml folder
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference android:key="checkbox"
android:title="Title"/>
</PreferenceScreen>

Related

Add fragment to programmatically generated FrameLayout

I have inherited some code that requires a change in how it works. The original way didn't have the flexibility now required.
The application is a form generator, and hence has to create the UI on demand. This is Xamarin native, not Xamarin forms.
A FrameLayout for each form question is being created programmatically, added to the view, then a fragment is being added to this FrameLayout. All this is happening AFTER OnCreateView once the UI has been loaded to show a progress circle.
After working through a bunch of exceptions, I have become stuck with the exception
Java.Lang.IllegalArgumentException: No view found for id 0x50 (unknown) for fragment UploadFragment{a31e878 #7 id=0x50 upload_80}
My guess is that the FrameLayout doesn't exist when the fragment is trying to be displayed.
The exception occurs after the OnCreate() method runs after OnCreateView() completes.
I have not been able to find any code precedent for adding FrameLayouts programmatically with Fragments.
CODE Snippet
frame = new FrameLayout(this.Context);
frame.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
upload = new Widgets.UploadFragment(control, binding, Inflater, a, xFormInstance);
MainFormLayout.AddView(frame);
frame.Id = control.id;
fragmentTx.Add(frame.Id, upload, $"upload_{control.id}");
fragmentTx.Commit();
Any advice would be greatly appreciated. Thanks.
Extended Explanation
It may be a bit much to put in everything it does, but will try and put in as much as I can.
The Hierarchy of the page is
Activity -> FormFragment -> UploadFragment
So the parent of the UploadFragment is also a fragment, not the Activity.
Upload Fragment
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout>
<LinearLayout>
<TextView/>
<ImageButton/>
</LinearLayout>
<ImageView/>
</RelativeLayout>
</LinearLayout>
CODE
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
_inflater = inflater;
v = _inflater.Inflate(Resource.Layout.BindImageInput, container, false);
SetUpload();
return v;
//return base.OnCreateView(inflater, container, savedInstanceState);
}
SetUpload() Sets the values of the label, the events for the buttons, and the image (if exists) to the imageview. It also deals with a few extra events to do with form event handling. Stopping SetUpload() from running still has the exception occur.
FormFragment
<RelativeLayout>
<TextView />
<View />
<ScrollView>
<LinearLayout />
</ScrollView>
</RelativeLayout>
CODE
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ShowLoading();
View v = inflater.Inflate(Resource.Layout.Form2, container, false);
MainFormLayout = v.FindViewById<LinearLayout>(Resource.Id.mainFormView);
MainScrollView = v.FindViewById<ScrollView>(Resource.Id.mainScrollView);
formBuilderWorker = new BackgroundWorker();
return v;
}
OnResume() Calls the method where formBuilderWorker.DoWork() exists
formBuilderWorker.DoWork += delegate
{
Form.LoadForm(null, this, FormInstance);
}
LoadForm() uses a Interface to tell the FormFragment to display a control. One of which is the UploadFragment.
public void AddControl(Controls control, int? sectionID)
{
///CODE REMOVED FOR OTHER CONTROL TYPES (they still use old codebase)
Bindings binding = XForm.GetBindingForControl(control, FormInstance);
try
{
// Create a new fragment and a transaction.
FragmentTransaction fragmentTx = this.FragmentManager.BeginTransaction();
FrameLayout frame = null;
Widgets.UploadFragment upload = null;
frame = new FrameLayout(this.Context);
frame.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
frame.Id = control.id;
upload = new Widgets.UploadFragment(control, binding, Inflater, a, xFormInstance);
MainFormLayout.AddView(frame);
ControlViews.Add(frame);
fragmentTx.Replace(frame.Id, upload, $"upload_{control.id}");
//fragmentTx.Show(upload);
fragmentTx.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
This is cleaned code to remove as much irrelevant code as possible. The code shown is the path the code in question moves through.
I found the issue. Part of what I took out of the code above, was the Activity.RunOnUiThread() calls that add the frame to the main view. The issue was caused by Thread Timing. The UI thread was taking so long to add the frame to the view, that when the FragmentTransaction was trying to commit the changes, the frame still did not exist.

Xamarin.Android Change ImageButton when press and release, (Error with button click not working anymore)

So I tried to change the image of imageButton when on press and release, it works. But the Button.Click function won't execute/trigger anymore after I implement the code, here's my code
ImageButton btnNewGame;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
btnNewGame = FindViewById<ImageButton>(Resource.Id.btnNewGame);
btnNewGame.Click += BtnNewGame_Click;
btnNewGame.Touch += (object sender, View.TouchEventArgs e) =>
{
if (e.Event.Action == MotionEventActions.Down)
{
btnNewGame.SetImageResource(Resource.Drawable.Button_New_Game_Pressed);
}
else if (e.Event.Action == MotionEventActions.Up)
{
btnNewGame.SetImageResource(Android.Resource.Drawable.IcMenuGallery);
}
};
private void BtnNewGame_Click(object sender, EventArgs e)
{
Intent nextActivity = new Intent(this, typeof(NextPage));
StartActivity(nextActivity);
}
Can someone please tell me why?
Thank you!
You can accomplish that using selectors.
Create a XML file inside the Drawables directory.
imagebutton_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:drawable="#drawable/ic_assignment_returned_black_24dp" />
<item
android:state_pressed="true"
android:state_enabled="true"
android:drawable="#drawable/ic_assignment_turned_in_black_24dp" />
<item
android:state_focused="true"
android:state_enabled="true"
android:drawable="#drawable/ic_assignment_returned_black_24dp" />
<item
android:state_enabled="true"
android:drawable="#drawable/ic_assignment_returned_black_24dp" />
</selector>
In this file you select the different states of the object, in your case the ImageButton.
I am defining 4 different states, you can define the ones you need and with different drawables each one, for simplicity I used the same drawable for 3 states (disabled, enabled and enabled + focused) and for pressed used a second drawable.
Now go to your Layout where the ImageButton is defined and set this as the background
<ImageButton
android:id="#+id/btnNewGame"
android:background="#drawable/imagebutton_selector"
android:layout_width="80dp"
android:layout_height="80dp" />
With this you are free to remove the OnTouch implementation on code and the Click event will continue working.
Hope this helps!

How do you make a popup menu on a ListView item?

How do you make a menu popup appear when you click a listview item, and have the menu popup under the item that you clicked?
Is it possible to do this using the ListView.ItemClick event to do this?
This question is for api 22+.
There have been many answers for this question but all that I have found are on old APIs, so this is how I did it.
It is possible to do it using the ListView.ItemClick event, and achieve a menu as shown.
(Names deleted)
[Activity(Label = "Employee Management", Theme = "#android:style/Theme.Material")]
public class EmpMgmtActivity : Activity
{
ListView empListView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.EmpMgmtLayout);
empListView = FindViewById<ListView>(Resource.Id.EmpMgmtList);
GenerateEmpList(EmployeeStorage.employeeList);
empListView.ItemClick += EmpListView_ItemClick;
}
private void EmpListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
var menu = new PopupMenu(this, empListView.GetChildAt(e.Position));
menu.Inflate(Resource.Layout.popup_menu);
menu.MenuItemClick += (s, a) =>
{
switch (a.Item.ItemId)
{
case Resource.Id.pop_button1:
// update stuff
break;
case Resource.Id.pop_button2:
// delete stuff
break;
}
};
menu.Show();
}
Most of this information is fairly easy to find, the part I had trouble with isnt getting the menu to popup but to have it popup on the right line item. The key for me was to lookup the individual view from the list.
var menu = new PopupMenu(this, empListView.GetChildAt(e.Position));
If you use
(View)Sender
Which comes in the even args, it will place the menu near the top of the page, which is not ideal.
Therefore using
ListView.GetChildAt(e.Position)
Which returns the actual view of the list item, you can have the menu popup in the correct location.
XML Code for the popup menu:
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/pop_button1" android:title="Edit Employee" showAsAction="always" />
<item android:id="#+id/pop_button2" android:title="Delete Employee" showAsAction="always" />
</menu>
Hope this helps!

How to remove (Android) app title bar in Xamarin.Forms?

Is there any chance that I can remove the title bar of the app in Xamarin.Forms? I am working on a Xamarin.Forms Portable project. I tried a lot of solutions, but neither worked, I couldn't even start the app.
First attempt I tried adding this to my AndroidManifest.xml, didn't work:
android:theme="#android:style/Theme.NoTitleBar"
Second attempt I tried creating a styles.xml in Resources/values, which was:
<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme.Default" parent="#android:style/Theme"></style>
<style name="Theme.NoTitle" parent="#android:style/Theme.NoTitleBar"></style>
<style name="Theme.FullScreen" parent="#android:style/Theme.NoTitleBar.Fullscreen"></style>
</resources>
And then I added this to my AndroidManifest.xml (didn't work either)
android:theme="#style/Theme.NoTitle"
Third attempt I tried adding this to my OnCreate method in MainActivity.cs (didn't work).
RequestWindowFeature(WindowFeatures.NoTitle);
Can anyone help me with this?
If you want to remove the title bar on the initial page, the quickest and easiest way to do it is to go to to the contentpage heading in your XAML for the page and type
NavigationPage.HasNavigationBar="False"
so the XAML would like something like this
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourClass.YourPage"
NavigationPage.HasNavigationBar="False">
This can be done in PCL:
var page = new LoginPage();
NavigationPage.SetHasNavigationBar(page, false); // call this method every time before you push a page (no title bar)
await navigation.PushAsync(page);
If you are using old FormsApplicationActivity,
try, add this in OnCreate(Bundle bundle) method
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle)
Forms.SetTitleBarVisibility(AndroidTitleBarVisibility.Never);
Forms.Init(this, bundle);
}
This one seems do the app wide setting, but I am not so sure, as I don't use FormsApplicationActivity anymore.
Using the latest version of Xamarin.Forms I found that if you use:
await Navigation.PushAsync(new NextPage())
//Title on NextPage is displayed
await Navigation.PushModalAsync(new NextPage())
//Title on NextPage is not displayed
Nathan
i had this problem before and my solution was adding this line of code to the MainPage.xaml NavigationPage.HasNavigationBar="False"
<?xml version="1.0" encoding="utf-8" ?>
<xf:BottomBarPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xf="clr-namespace:BottomBar.XamarinForms;assembly=BottomBar.XamarinForms"
xmlns:local="clr-namespace:App;assembly=App"
NavigationPage.HasNavigationBar="False" <-- This line !-->
x:Class="App.MainPage">
and it worked for me !
Theme = "#android:style/Theme.NoTitleBar"
.
using Android.App;
using Android.OS;
using Android.Webkit;
using Android.Views; // Webkit required for WebView
namespace LoadWebPage {
[Activity(Label = "LoadWebPage", MainLauncher = true, Icon = "#drawable/icon", Theme = "#android:style/Theme.NoTitleBar")]
public class Activity1 : Activity {
protected override void OnCreate (Bundle bundle)
For iOS this single line (e.g. in the constructor of the page) works just fine.
NavigationPage.SetHasNavigationBar(page, false);
But Android is ignoring it, also when put in the XAML of the page.
As mentioned above by Bonelol this method has to be called each time before you push a page.
I use Prism, so I can't access the creation and push of a page.
So I just created a custom renderer for NavigationPage and put this line there. Maybe this will help someone else.
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))]
namespace MyApp.Droid.Renderer
{
public class CustomNavigationRenderer : NavigationPageRenderer
{
public CustomNavigationRenderer(Context context) : base(context)
{
}
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
NavigationPage.SetHasNavigationBar(view, false);
return base.OnPushAsync(view, animated);
}
}
}
Try This:
private ActionBar ab;
protected override void OnCreate(Bundle savedInstanceState)
{
try
{
base.OnCreate(savedInstanceState);
ab = this.ActionBar;
ab.Hide();
}
catch (Exception ex)
{
}
}
Try this one, just found it in one of view xaml in flyout tab
Shell.NavBarIsVisible="False"
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="YourClass.Views.YourPage" Shell.NavBarIsVisible="False">

Can't load image in ImageViewAsync

I can't get an image to load into an ImageViewAsync. There's just a blank where the image should be. I've tried both synchronous and asychronous approaches.
I have the image placeholderProfileImage.png in the mipmap folders. I walked the debugger through the binding code and all appears to be in order. Note that I removed other code that populates the view with text. That part is working. What am I doing wrong with respect to the image?
profilePhotoImageView is defined in a layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/acquaintanceRow"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center">
<FFImageLoading.Views.ImageViewAsync
android:id="#+id/profilePhotoImageView"
android:scaleType="fitCenter"
android:layout_width="50dp"
android:layout_height="100dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:transitionName="#string/profilePhotoTransition" />
>
The view holder class contains ProfilePhotoImageView:
internal class MyViewHolder : RecyclerView.ViewHolder
{
// removed stuff for brevity
public ImageViewAsync ProfilePhotoImageView { get; }
public MyViewHolder(View itemView) : base(itemView)
{
MyRow = itemView;
// removed stuff for brevity
ProfilePhotoImageView = MyRow.FindViewById<ImageViewAsync>(Resource.Id.profilePhotoImageView);
}
}
Binding code:
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
var viewHolder = holder as MyViewHolder;
string photoUrl = "placeholderProfileImage.png:";
FFImageLoading.Work.TaskParameter taskParameter = ImageService.LoadFileFromApplicationBundle(photoUrl);
FFImageLoading.Work.TaskParameter taskParameter2 = taskParameter.Transform(new CircleTransformation());
taskParameter2.Into(viewHolder.ProfilePhotoImageView);
// tried asynchronous as well, nothing
//FFImageLoading.Work.TaskParameter taskParameter = ImageService.LoadUrl(photoUrl);
//FFImageLoading.Work.TaskParameter taskParameter2 = taskParameter.Transform(new CircleTransformation());
//taskParameter2.Into(viewHolder.ProfilePhotoImageView);
}
LoadFileFromApplicationBundle is loading the file from Assets not the mipmap folder. So you have to move the file to your Assets folder and set the build action to AndroidAsset.

Categories