Material BottomAppBar - events

I am trying to build a functional BottomAppBar in Android Java.
All it seems to work except that I don´t know how to put a listener in the items of bottomMenu.
The Material.io documentation is incomplete in this part.
follow my code:
public class MainActivity extends AppCompatActivity {
private BottomAppBar bottomAppBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bottomAppBar = findViewById(R.id.bottomAppBar);
bottomAppBar.setNavigationOnClickListener(new *OnClickListener()* {
#Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "TEste da bottom bar", Toast.LENGTH_SHORT).show();
}
});
bottomAppBar.setOnMenuItemClickListener(new *OnMenuItemClickListener()* {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.item_relatorio:
Toast.makeText(getApplicationContext(),"Item relatorio",Toast.LENGTH_LONG).show();
break;
case R.id.item_sobre:
Toast.makeText(getApplicationContext(),"Item sobre",Toast.LENGTH_LONG).show();
break;
case R.id.item_sair:
Toast.makeText(getApplicationContext(),"Item sair",Toast.LENGTH_LONG).show();
break;
}
return false;
}
});
This is my activity_main.XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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"
android:background="#drawable/greengrasstexture"
tools:context=".MainActivity">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="10dp"
app:fabCradleVerticalOffset="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="BottomAppBar">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/bottomNavigation"
android:layout_marginRight="0dp"
app:menu="#menu/menu_bottom"
android:background="#color/white"/>
</com.google.android.material.bottomappbar.BottomAppBar>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
follow my menu_bottom
<?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/item_CadLogin"
android:icon="#drawable/ic_login_24"
android:orderInCategory="100"
android:title="cadastro/login"
app:showAsAction="always"
/>
<item
android:id="#+id/item_preferencias"
android:icon="#drawable/ic_baseline_construction_24"
android:orderInCategory="200"
android:title="preferências"
app:showAsAction="always"
/>
<item
android:id="#+id/item_conta"
android:icon="#drawable/ic_baseline_account_circle_24"
android:orderInCategory="300"
android:title="Conta"
app:showAsAction="always"
/>
</menu>
Finally, from Material.io docs, the incomplete code:
(in kotlin i presume, but i need it in java)
bottomAppBar.setNavigationOnClickListener {
// Handle navigation icon press
}
bottomAppBar.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.search -> {
// Handle search icon press
true
}
R.id.more -> {
// Handle more item (inside overflow menu) press
true
All the tutorials, stops focused just on how to build th BottomAppBar but not in how to implements click functionality to the menu icons.
Thanks in advance for any help.

Related

How to customize TabBar (TabLayout) in different page - xamarin

Is it possible to implement app:tabMode="scrollable" in specific page only? I have 2 page that contains TabBar and the other one should be in fixed mode only.
I created a custom TabBar and in Android and it is deployed on all my TabBar page.
My customTabBar.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="80dp"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="#FF3300"
app:tabTextAppearance="#style/CustomTab"
app:tabMode="scrollable" />
And for my MainActivity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
AppCompatDelegate.DefaultNightMode = AppCompatDelegate.ModeNightNo;
TabLayoutResource = Resource.Layout.CustomTabbar;
LoadApplication(new App());
}

Data binding in custom view throws and error in Android Studio preview

I have created a custom view that uses data binding. It works fine in the application but it throws an error in the Android studio IDE.
DataBindingUtil.inflate throws an error because some of the fields in the binding are null in edit mode.
I can get around this by using isInEditMode and using normal inflate when it edit mode. However, that means that the preview is never accurate because no data is bound to the fields. If I try to skirt around data binding in edit mode and then poke in values directly then "why use data binding at all"?
Is there a way to use data binding in a custom view and get an accurate preview in the IDE?
public class HelpItem extends LinearLayoutCompat {
private String mText = "Dog";
private Drawable mDrawable;
public HelpItem(Context context) {
super(context);
init(context, null, 0);
}
public HelpItem(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public HelpItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void getStyleableAttributes(Context context, AttributeSet attrs) {
if (null != attrs) {
TypedArray attributes = context.obtainStyledAttributes(attrs,
R.styleable.HelpItem);
mDrawable = attributes.getDrawable(R.styleable.HelpItem_helpItemIcon);
mText = attributes.getString(R.styleable.HelpItem_helpItemText);
attributes.recycle();
}
}
private void init(Context context, AttributeSet attrs, #SuppressWarnings("unused") int defStyle) {
getStyleableAttributes(context, attrs);
LayoutInflater factory = LayoutInflater.from(context);
// if (isInEditMode())
// inflate(context, R.layout.view_help_item, this);
// else {
ViewHelpItemBinding binding = DataBindingUtil.inflate(factory, R.layout.view_help_item, this, true);
binding.setText(mText);
binding.setIcon(mDrawable);
ImageView iv = binding.getRoot().findViewById(R.id.help_icon);
if (null != iv) iv.setImageDrawable(mDrawable);
// }
}
}
Here is my custom view layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<data>
<variable
name="icon"
type="android.graphics.drawable.Drawable" />
<variable
name="text"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="20dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp"
>
<ImageView
android:id="#+id/help_icon"
android:layout_width="70dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
app:icon="#{icon}"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
style="#style/ContactTextBold"
android:text="#{text}"
tools:text="#string/title_help_getting_started"
android:textColor="#color/textColor"
android:textSize="20sp"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="20dp"
app:srcCompat="#drawable/ic_baseline_keyboard_arrow_right_24px"
/>
</LinearLayout>
<include layout="#layout/seperator_view_gray" />
</LinearLayout>
</layout>
Here is an example of how I include the custom view in a layout
<com.apcon.intellaviewmobile.view.HelpItem
android:id="#+id/getting_started"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:helpItemIcon="#drawable/ic_arrow_right"
app:helpItemText="#string/title_help_getting_started"
/>
Here is the error being thrown in the IDE
java.lang.NullPointerException
at com.apcon.intellaviewmobile.databinding.ViewHelpItemBindingImpl.<init>(ViewHelpItemBindingImpl.java:35)
at com.apcon.intellaviewmobile.databinding.ViewHelpItemBindingImpl.<init>(ViewHelpItemBindingImpl.java:29)
at com.apcon.intellaviewmobile.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:118)
at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
at androidx.databinding.DataBindingUtil.bindToAddedViews(DataBindingUtil.java:327)
at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:128)
at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:95)
at com.apcon.intellaviewmobile.view.HelpItem.init(HelpItem.java:51)
at com.apcon.intellaviewmobile.view.HelpItem.<init>(HelpItem.java:27)
at sun.reflect.GeneratedConstructorAccessor1708.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:403)
at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:186)
at org.jetbrains.android.uipreview.ViewLoader.loadView(ViewLoader.java:144)
at com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadView(LayoutlibCallbackImpl.java:309)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:418)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:429)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:333)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:863)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:72)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:837)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:866)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:72)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:837)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:394)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:326)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:391)
at com.android.tools.idea.layoutlib.LayoutLibrary.createSession(LayoutLibrary.java:195)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:540)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$5(RenderTask.java:666)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Actual results: The IDE throws an error when previewing
Desired results: To be able to use data binding in a custom view and see WYSIWIG preview in Android Studio.
Android Studio Chipmunk doesnt have problem.
Android Studio Dolphin and Electric Eel have this CustomView databinding preview problem
According to this https://issuetracker.google.com/issues/260134720, Android Flamingo also doesnt have has problem, but it's still in beta
Im currently downgrade this Chipmunk version and it's working well
Android Studio Chipmunk | 2021.2.1 May 9, 2022
You can download archive from here https://developer.android.com/studio/archive

How to fix Resource versus Resources error in Xamarin - Visual Studio

I have a very simple Xamarin Android app. It has a text box and a button. Here's the activity_main.axml file in Resources.Layout:
<?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"
android:orientation="vertical">
<TextView
android:text="0"
android:textSize="50sp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/txtNumber"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp" />
<Button
android:text="Get Number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/btnAutoGenerate" />
In the Solution Explorer I have Assets and Resources.
Under Resources is layout and under layout is activity_main.axml
Not complex at all.
In MainActivity.cs, the OnCreate procedure is this:
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TextView txtNumber;
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
txtkNumber = FindViewById<TextView>(Resource.Id.txtNumber);
FindViewById<Button>(Resource.Id.btnAutoGenerate).Click += (o, e) =>
txtNumber.Text = btnAutoGenerate_Click(o, e);
}
I'm not sure where Resource is defined (as in the xml it's Resources) but even though at first this compiled with no problem now I get the error: the name "Resource" does not exist in the current context.
Because when the default files are first generated, it is
SetContentView(Resource.Layout.activity_main);
even though the "Resource.Layout" is pointing to Resources.layout. Not sure why.

Unhandled exception in xamarin forms app after setting SetContentView

I need to place my app icon on the left side of the toolbar, so I placed an ImageButton in Toolbar.axml. I set the SetContentView so that I can access the ImageButton using FindViewById and Listen to the click event.
But After adding the SetContentView line my app throws UnhandledException.
Below is my Main.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<ImageButton
android:src="#drawable/appicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:id="#+id/homeicon" />
</android.support.v7.widget.Toolbar>
</LinearLayout>
And my MainActivity.cs is like below:
[Activity(Label = "XamarinToolBar", Icon = "#drawable/icon", Theme =
"#style/MainTheme", MainLauncher = true, ConfigurationChanges =
ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
//TabLayoutResource = Resource.Layout.Tabbar;
//ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
ImageButton homeButton = (ImageButton)FindViewById<ImageButton>(Resource.Id.homeicon);
homeButton.Click += HomeButton_Click;
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
private void HomeButton_Click(object sender, EventArgs e)
{
}
}
The Problem is here :
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
You are mixing up the xamarin forms FormsAppCompatActivity with your AppCompactActivity and remove these two lines from your cs file
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
I hope it helps
Goodluck!
i think you are trying to mix and match the xamarin.forms "FormsAppCompatActivity" and make it behave like a normal android Activity in which shouldn't be the case because xamarin.forms "FormsAppCompatActivity" has its own underlying rendering engine through the use of xaml pages (e.g. ContentPage, MasterDetailPage etc.). Try to create an Android project instead.

CallygraphyXamarin not working in MvxAppCompatActivity

I've have been trying for hours to get the custom fonts working in my MvvmCross project, specifically the Android platform.
I successfully installed the component and followed the steps mentioned:
https://components.xamarin.com/gettingstarted/calligraphyxamarin
It just doesn't want to work.
I tested it on a activity than inherits from Activity and AppCompatActivity they both work correctly.
Seems like inheriting from MvxAppCompatActivity breaks it? Any solutions this this problem?
Update
I released a nuget package for this (see: MvvmCross.Calligraphy).
Sample project: https://github.com/smstuebe/mvvmcross-calligraphy.
Blog post: http://smstuebe.de/2017/02/12/mvvmcross-calligraphy/
Just download it and modify your setup like:
public class Setup : MvxAndroidSetup
{
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new CalligraphyMvxAndroidBindingBuilder();
}
}
Yes, because MvvmCross uses a custom layout inflator to bring in the bindings and some other magic stuff. This kicks out the Calligraphy inflator. Unfortunately, I didn't find a way usining the nuget package / xamarin component. You have to create a own binding and make CalligraphyFactory available.
Modified metadata.xml
<attr path="/api/package[#name='uk.co.chrisjenx.calligraphy']/class[#name='CalligraphyFactory']"
name="visibility">public</attr>
Custom factory
public class MyFactory : MvxAndroidViewFactory
{
private CalligraphyFactory _factory;
public MyFactory()
{
_factory = new Calligraphy.CalligraphyFactory(Resource.Attribute.fontPath);
}
public override View CreateView(View parent, string name, Context context, IAttributeSet attrs)
{
var view = base.CreateView(parent, name, context, attrs);
view = _factory.OnViewCreated(view, context, attrs);
return view;
}
}
Custom binding builder
class MyBindingBuilder : MvxAndroidBindingBuilder
{
protected override IMvxAndroidViewFactory CreateAndroidViewFactory()
{
return new MyFactory();
}
}
Setup.cs
public class Setup : MvxAndroidSetup
{
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyBindingBuilder();
}
// ...
}
Activity
You don't need AttachBaseContext. Unfortunately it seems not to work with MvxAppCompatActivity, but with MvxActivity. I'm not sure what causes this issue, yet.
public class FirstView : MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
CalligraphyConfig.InitDefault(new CalligraphyConfig.Builder()
.SetDefaultFontPath("fonts/gtw.ttf")
.SetFontAttrId(Resource.Attribute.fontPath)
.DisablePrivateFactoryInjection()
.Build());
SetContentView(Resource.Layout.FirstView);
}
}
View
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
fontPath="fonts/gtw.ttf"
/>
</LinearLayout>
Result
Using Calligraphy and MvvmCross together is overkill because MvvmCross uses a custom layout inflator to bring in the bindings you can easily bind custom fonts to TextView typeface by a custom converter.
public class StringToFontConverter : MvxValueConverter<string, Typeface>
{
private static readonly Dictionary<string, Typeface> Cache = new Dictionary<string, Typeface>();
protected override Typeface Convert(string fontName, Type targetType, object parameter, CultureInfo culture) {
try {
if (!fontName.StartsWith(#"fonts/")) fontName = #"fonts/" + fontName;
if (!fontName.EndsWith(".ttf")) fontName += ".ttf";
if (!Cache.ContainsKey(fontName))
Cache[fontName] = Typeface.CreateFromAsset(Application.Context.Assets, fontName);
return Cache[fontName];
} catch {
return Typeface.Default;
}
}
}
And use it in layout:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="Typeface StringToFont('Roboto-Light')"/>
Or in styles:
<style name="CustomTextViewStyle" parent="#android:style/Widget.TextView">
<item name="MvxBind">"Typeface StringToFont('Roboto-Regular')"</item>
</style>
Calligraphy library does the same work, override layout inflate process and change TextView typeface, so it's undesirable to add next library and increase apk weight.

Resources