how can i use lottie animation in custom progress dialog.
i know how implement custom progress bar with lottie but i want progress dialog.
i have my animation in json format. but i dont know how make custom progress dialog.
in gradle i write this line
implementation 'com.airbnb.android:lottie:3.4.4'
and new class
import android.app.ProgressDialog;
import android.content.Context;
import android.view.animation.Animation;
public class MyProgressDialog extends ProgressDialog {
public MyProgressDialog(Context context) {
super(context,R.style.NewDialog);
// TODO Auto-generated constructor stub
}
}
i found this video but it is coded by kotlin. i want use java
https://www.youtube.com/watch?v=ZcR6AMNIagU
i found solution
1- make one xml layout for new design. "loading.json" is json format of animation in asset folder.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="100dp"
>
<com.airbnb.lottie.LottieAnimationView
android:id="#+id/progressAnimationView"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_fileName="loading.json"
app:lottie_loop="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
2-create new java class
public class lottiedialogfragment extends Dialog {
public lottiedialogfragment(Context context) {
super(context);
WindowManager.LayoutParams wlmp = getWindow().getAttributes();
wlmp.gravity = Gravity.CENTER_HORIZONTAL;
getWindow().setAttributes(wlmp);
getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
setTitle(null);
setCancelable(false);
setOnCancelListener(null);
View view = LayoutInflater.from(context).inflate(
R.layout.dialog_lottie, null);
setContentView(view);
}
}
3-call dialog in main activity
final lottiedialogfragment lottie=new lottiedialogfragment(this);
lottie.show();
You can create it easily using the LottieDialog library
Code will be like this
LottieDialog dialog = new LottieDialog(this)
.setAnimation(R.raw.ripple)
.setAutoPlayAnimation(true)
.setDialogHeightPercentage(.2f)
.setAnimationRepeatCount(LottieDialog.INFINITE)
.setMessage("Loading...")
.setMessageColor(orangeColor);
dialog.show();
Github Repo for examples and documentation : LottieDialog
End result will be like this
Related
I have the following simple recyclerview layout:
<RelativeLayout
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"
tools:context=".SurvivorPicksheetActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
This recycler view links to the detailed layout of the list items as such:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout 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:id="#+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_centerHorizontal="true"
app:srcCompat="#drawable/gamefield_background" />
<ImageView
android:id="#+id/away"
android:layout_width="160dp"
android:layout_height="150dp"
android:layout_gravity="top|left"/>
<ImageView
android:id="#+id/home"
android:layout_width="160dp"
android:layout_height="150dp"
android:layout_gravity="top|right"
android:scaleX="-1"/>
</androidx.cardview.widget.CardView>
</FrameLayout>
</LinearLayout>
Inside my Adapter java class I have an setOnClickListener for the two ImageView items.
If a user clicks on them the item is selected while the old item is unselected.
The problem I am encountering if that lets say the list of items has 25 items. If I click on the lets say 3rd item, everything works as expected.
Then I scroll to the end of the list, and scroll back up to the top, the selection is not longer valid even thought I clicked/selected prior to scrolling to the end of the list.
I can reclick and item at the top, scroll down and scroll back up and my selection is gone!?
Does anyone know why this is happening and more importantly how i can resolve it!?
UPDATE:
The following is my Adapter class:
public class GameAdapter extends
RecyclerView.Adapter<GameAdapter.GameViewHolder> {
// variable that holds the selected team
private String selectedTeam = "";
#Override
public void onBindViewHolder(GameViewHolder holder, int position) {
final Games game = gameList.get(position);
holder.awayTeamImageView.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
if (selectedTeam.equals(String.valueOf(game.getHomeId()))) {
// RESET PLAYER SELECTION
selectedTeam = "";
selectedGame = "";
} else {
// SET PLAYER SELECTION
selectedTeam = String.valueOf(game.getHomeId());
selectedGame = String.valueOf(game.getKey());
}
}
}
}
class GameViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public GameViewHolder(#NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(this);
awayImageView = itemView.findViewById(R.id.away);
homeImageView = itemView.findViewById(R.id.home);
homeImageView.setOnClickListener(this);
awayImageView.setOnClickListener(this);
}
}
Based on my code above, I 'think' I am setting and unsetting the selected team so that when I scroll to the end and back to the top the selected team should remain vs being recycled and not displaying anymore?!
That's because the old Views are being recycled, back to the initial state. And this is a natutral behavior of RecyclerView.
In order to make each item View "memorize" its check/select state, you need to create a field in your model class to record the state, like isChecked or isSelected.
You can use own domain ViewHolder and ViewModel for recycleview.
Android developer documents gives basic understanding of how to create dynamic RecycleView in below link.
https://developer.android.com/guide/topics/ui/layout/recyclerview
This is expected as the views are recycled and lose their values accordingly whenever you scroll up/down the list; further for configuration changes (like screen rotation) the selected views will be lost.
To fix this, you should go for ViewModel to have persistent data even for configuration changes.
But, as a rescuer, assuming the adapter provided list of games gameList is in a persistent storage like mentioned above; then you can:
Create a selection boolean in the Games model class with getter/setter which has a false initially.
When a row is selected from the RecyclerView, then set the boolean to true like gameList.get(selectedPosition).setIsSelected(true)
Then notifyItemChanged() of that position.
I know this is a simple question but I'm a beginner and I have this homework where we
have to make an image show when the radio button is clicked but they didn't teach us anything about that
because of coronavirus so I would really appreciate it if someone could tell me how to do it.
For creating two radio buttons with simple image, and control visibility of image when check one of the radio buttons, I will give some simple steps to build that in java.
After build a new empty activity project:
You can open the wanted files from project explorer as shown :
go to activity_main.xml which is the layout file, I will create Linear layout with image and radio group contains two radio buttons,and I used imageview android:src attribute as a color (you can change it to image):
<ImageView
android:id="#+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#color/colorPrimary"
android:text="Hello World!"
android:visibility="gone" />
<RadioGroup
android:id="#+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="horizontal">
<RadioButton
android:id="#+id/radio_button_choice1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="choice-1" />
<RadioButton
android:id="#+id/radio_button_choice2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="choice-2" />
</RadioGroup>
Second, we need to go to java file named as MainActivity which is java file, and we will get the views and create a listener on the RadioGroup which we will use to show and hide the image (some comments help you understands the java code):
package com.your.packagename.here;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioGroup;
public class MainActivity extends AppCompatActivity {
private ImageView image;
private RadioGroup radioGroup;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//intit views
image = findViewById(R.id.imageView);
radioGroup = findViewById(R.id.radioGroup);
//create the listener for radio group
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
//check if the choice-1 is selected
if (radioGroup.getCheckedRadioButtonId() == R.id.radio_button_choice1) {
//show image wen select choice-1
image.setVisibility(View.VISIBLE);
} else {
//hide image when choice-1 not selected
image.setVisibility(View.GONE);
}
}
});
}
}
Finally, and you will get similar to this.
I hope this was helped you.
I have a simple android project where I'm populating a list of items in a database. To do this I'm using RecyclerView showing in my activity_main.xml
These are my two (and only two that exist) xml files
activity_main.xml
package com.twocrows.foretoldapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.twocrows.foretoldapp.adapter.ChartAdapter;
import com.twocrows.foretoldapp.entity.Chart;
import com.twocrows.foretoldapp.viewmodel.ChartViewModel;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ChartViewModel chartViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final ChartAdapter adapter = new ChartAdapter();
recyclerView.setAdapter(adapter);
chartViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(ChartViewModel.class);
chartViewModel.getAllCharts().observe(this, new Observer<List<Chart>>() {
#Override
public void onChanged(List<Chart> charts) {
adapter.setCharts(charts);
}
});
}
}
which shows in the preview like this
chart_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="#+id/text_view_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text="location"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="#+id/text_view_name"
android:layout_width="139dp"
android:layout_height="38dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginEnd="248dp"
android:layout_marginRight="248dp"
android:layout_below="#+id/text_view_name"
android:text="Chart Name"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
tools:ignore="NotSibling" />
<TextView
android:id="#+id/text_view_dateTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_view_name"
android:text="MM/DD/YYYY"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
MainActivity.java
package com.twocrows.foretoldapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.twocrows.foretoldapp.adapter.ChartAdapter;
import com.twocrows.foretoldapp.entity.Chart;
import com.twocrows.foretoldapp.viewmodel.ChartViewModel;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ChartViewModel chartViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final ChartAdapter adapter = new ChartAdapter();
recyclerView.setAdapter(adapter);
chartViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(ChartViewModel.class);
chartViewModel.getAllCharts().observe(this, new Observer<List<Chart>>() {
#Override
public void onChanged(List<Chart> charts) {
adapter.setCharts(charts);
}
});
}
}
The issue is that whenever I try to run the app, it's showing me an old version of the main activity xml file. I no longer even have these components in the xml so I don't understand where they are coming from.
#Things I've tried
Invalidate cache/ restart
clean build
edit configuration, uncheck 'skip installation if apk has not changed'
Nothing so far has worked. Any help would be appreciated. Thanks!
The issue of your app showing an old version of the activity_main.xml, even though you no longer have those components in the file, may be due to having two different layout resource files for a single activity.
You can check your layout resource directory to see if you have two different versions of the main activity layout file, such as "main.xml" and "main.xml(v21)", which may be causing the confusion. You can see the reason for having multiple files in this answer.
In this case, the solution would be to make sure that you're editing the correct layout file. If you edited an XML file but your emulator is running the v21 file, you can copy your code and paste it into the other file.
If you've made changes to the correct file but are still seeing the old version in the emulator, you can try cleaning and rebuilding the project, or even deleting the app from the emulator and reinstalling it.
If you continue to experience the issue, you may also want to check the AndroidManifest.xml file to ensure that the correct layout file is being used for the main activity. This file can be found in the "app" directory of your project.
I've been using the new Navigation Component since shortly after it has been announced at Google I/O, and also started to embrace the single-activity as much as possible.
The Single Activity allowed me to share ViewModels between view for an awesome experience and I really don't want to go back to multi-activity if I'm not forced to.
But there's something that gets in the way: AppBar / Themes (status bar) to the single activity concept.
This is part of the design I'm working in:
As you can see there are different requirments for how the Actionbar / status bar should look.
It's a simple drawer with standard actionbar
Classic detail with image going under the translucent status bar, supposed to use CollapsingToolbarLayout to turn into a standard actionbar when scrolling up
In this case it is non-standard actionbar, I'd call it a "floating toolbar" cause it doesn't expand to the full with of the screen and contains an already expanded SearchView / EditText
Fairly standard AppBar with tabs
List of issues that arise from leaving the single activity:
can't share ViewModels between activities
complex navigations which re-use parts already defined in another activity navigation graph have to be duplicated / moved into a dedicated activity
back navigation "re-construction" doesn't work between activities
Those are issues I want to avoid if possible, but how do you guys manage these kind of situation on a single-activity with navigation component. Any idea?
As mentioned here, the developer document said
Adding the top app bar to your activity works well when the app bar’s layout is similar for each destination in your app. If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.
I was also thinking the same but never got time to do some experiment. So it's not a solution, it's an experiment, where I want to replace a view with another, here, the toolbar with a toolbar that contains an ImageView.
So I created a new Application using "Basic Activity" template. Then created two destinations within the graph, Home and destination. And lastly, created another layout for Toolbar:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="?actionBarSize">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher_round" />
</androidx.appcompat.widget.Toolbar>
The activity_main.xml has:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
...
And then within Activity, of-course depends on the setup, but let's say that I want to setup an support-actionbar with toolbar:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
Toolbar toolbar2 = (Toolbar) getLayoutInflater().inflate(R.layout.destination_toolbar, null);
AppBarLayout appBarLayout = findViewById(R.id.appbar_layout);
navController = Navigation.findNavController(this, R.id.nav_host_fragment);
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph())
.build();
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
switch (destination.getId()) {
case R.id.homeFragment:
appBarLayout.removeAllViews();
appBarLayout.addView(toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("Home Fragment");
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
break;
case R.id.destinationFragment:
appBarLayout.removeAllViews();
appBarLayout.addView(toolbar2);
setSupportActionBar(toolbar2);
toolbar2.setTitle("");
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
break;
}
});
}
And thus, this works, making it somewhat ugly as destination grows and new Toolbar/any other view is being added.
P.S. As I told earlier, this is just an experiment, if anyone has a better solution, please do post a new answer.
Disclaimer
Based of #Rajarshi original experiment, I made a working solution for this problem. I'm not sure is the most elegant, or if there are better ways. But after hours of research and investigation, this is the best solution I found.
Solution
Inflate the toolbars separately and store their references so they are not picked by the garbage collector.
Then load each on demand in your main AppBarLayout inside a custom OnDestinationChangedListener defined for your navController
Example
Here's an example I've written in Kotlin.
On your activity.xml layout, define an AppBarLayout that is empty.
layout/activity.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
...
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay" />
...
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Define the toolbars that your app needs to have in separate layout files.
layout/toolbar_defaul.xml
<com.google.android.material.appbar.MaterialToolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/default_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:menu="#menu/menu_default"
app:popupTheme="#style/AppTheme.PopupOverlay" />
layout/toolbar2.xml
<com.google.android.material.appbar.MaterialToolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:menu="#menu/menu2"
app:popupTheme="#style/AppTheme.PopupOverlay" />
In your main (and only) activity, declare AppBar related components as class properties, so that they are not picked up by the garbage collector.
Activity.kt
class Activity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var appBarLayout: AppBarLayout
private lateinit var defaultToolbar: MaterialToolbar
private lateinit var toolbar2: MaterialToolbar
...
And finally, in the onCreate method, define a OnDestinationChangedListener for the navController. Use it to load on demand each toolbar.
Activity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ryvod)
// Set up AppBar
appBarLayout = findViewById(R.id.appbar)
appBarConfiguration = AppBarConfiguration(setOf(R.id.StartFragment))
defaultToolbar = layoutInflater.inflate(R.layout.toolbar_default, appBarLayout, false) as MaterialToolbar
toolbar2 = layoutInflater.inflate(R.layout.toolbar2, appBarLayout, false) as MaterialToolbar
val host =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
?: return
val navController = host.navController
navController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.locationPickerFragment -> {
appBarLayout.removeAllViews()
appBarLayout.addView(toolbar2)
setSupportActionBar(toolbar2)
}
else -> {
appBarLayout.removeAllViews()
appBarLayout.addView(defaultToolbar)
setSupportActionBar(defaultToolbar)
}
}
setupActionBarWithNavController(navController, appBarConfiguration)
}
}
That should do the trick
I confronted this problem a while ago, with similar UX/UI as yours:
Sidenav Navigation Drawer
A "normal" Appbar with back arrow
Translucent Appbar/status bar
My solution was having a different .xml Appbar for each case and using the <include/> tag inside every fragment xml:
<include
android:id="#+id/include"
layout="#layout/default_toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
The window config for case 1 and case 2 was the same, but for the translucent Appbar, the window config changed, see case 3.
So I had to do a config change every time the fragment showed up/replaced:
public static void transparentStatusBar(Activity activity, boolean isTransparent, boolean fullscreen) {
if (isTransparent){
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}else {
if (fullscreen){
View decorView = activity.getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
} else {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
| View.SYSTEM_UI_FLAG_VISIBLE);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}
And then use this method in translucent appbar/status bar fragment's lifecycle:
#Override
public void onResume() {
super.onResume();
UtilApp.transparentStatusBar(requireActivity(), true, true);
}
#Override
public void onStop() {
super.onStop();
UtilApp.transparentStatusBar(requireActivity(), false, false);
}
A couple of firsts here - first Android app and first time using MonoDroid (I've got lots of experience with C# .NET).
In my user interface I want to draw a border around a TextView and found a post on SO (2026873) that recommended subclassing TextView. I also found another post (2695646) with some additional info on declaring a custom Android UI element using XML. (Note: All code in the example posts were in Java, had to translate into the C#/MonoDroid environment.)
When I run the code in the emulator I get a System.NullReferenceException: Object reference not set to an instance of an object.
Here's my out-of-the-box Activity1 code and the code for the subclassed TextView.
namespace MBTA
{
[Activity(Label = "MBTA", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
}
}
public class BorderedTextView : TextView
{
public BorderedTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) { }
public BorderedTextView(Context context, IAttributeSet attrs) : base(context, attrs) { }
public BorderedTextview(Context context) : base(context) { }
protected override void OnDraw (Android.Graphics.Canvas canvas)
{
base.OnDraw (canvas);
Rect rect = new Rect();
Paint paint = new Paint();
paint.SetStyle(Android.Graphics.Paint.Style.Stoke);
paint.Color = Android.Graphics.Color.White;
paint.StrokeWidth = 3;
GetLocalVisibleRect(rect);
canvas.DrawRect(rect, paint);
}
}
}
My Main.axml layout is as follows:
<?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/MBTA"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<MBTA.BorderedTextView
android:text="DATE"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center_vertical"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
And my attrs.xml file is as follows (with its BuildAction set to AndroidResource):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BorderedTextView">
<attr name="android:text"/>
<attr name="android:textSize"/>
<attr name="android:layout_width"/>
<attr name="android:layout_height"/>
<attr name="android:gravity"/>
<attr name="android:layout_weight"/>
</declare-styleable>
</resources>
Thanks in advance.
Mono for Android lowercases the namespace name when generating the Java Android Callable Wrappers for use by Android and layout XML files.
Consequently (as noted in the previous answer), you need to use mbta.BorderedTextView, not MBTA.BorderedTextView.
The Mono for Android documentation discuses using custom views in a layout, which addresses this scenario.