Implement bottom drawer in android Java - java

I am unable to implement a bottom drawer in android (java) and can not find any working example/tutorial on its usage. Can you write sample code for using a bottom drawer? (https://material.io/components/navigation-drawer/#bottom-drawer)
Alternatively, I tried using a drop down menu but my app needs a bottom drawer only
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navbottom"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_gravity="bottom"
app:menu="#menu/menu_nav"> </com.google.android.material.bottomnavigation.BottomNavigationView>```
Here's the code to my bottom navigation view
This is how it should look like1

In the screenshot that you added, I saw something that looks like BottomSheet. To get this look of dialog you probably want to use BottomSheetDialogFragment so below I will explain how to implement it inside your Activity.
1) First of all, you need to create a class that will extend from BottomSheetDialogFragment and inflate the layout that will be used by this fragment.
public class ExampleBottomSheetDialog extends BottomSheetDialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
return inflater.inflate(*R.layout.bottom_sheet_layout*, container, false);
}
}
2) Then you need to create the *R.layout.bottom_sheet_layout* layout file that will hold needed views and provide logic for them if it's needed.
3) After that, you can programmatically set Dialog logic. So for example, you could open this dialog by pressing the button.
Button buttonDialogBottomSheet = findViewById(R.id.btn_sh_dialog);
buttonDialogBottomSheet.setOnClickListener((v) -> {
ExampleBottomSheetDialog bottomSheetDialog = new ExampleBottomSheetDialog();
bottomSheetDialog.show(getSupportFragmentManager(), "simple tag");
});
If you're looking for standard Bottom Sheet just let me know, I will update the answer.
Result of code written above:
link

Related

Putting a menu inside a Navmenu fragment java android

I'm developing a Java android app for my current school project. The app contains of a navigation menu with 3 sections.
One section contains a on swipe card view, second displays my jobs and the third one is account settings.
The second fragment my jobs is ment to be as follows:Form
The problem is how to set the top menu inside that certain fragment. My jobs should show one fragment containing "Jobs" that I am a part off, and the other menu option Jobs that I offer should show my listed jobs inside a recycler view and it should contain a button that opens the form to create a new job.
So far I filled up the fragment my jobs with the needed recycler view but I struggle with the menu itself.
problematic menu
Code for frag1:
public class MojiPosloviFragment extends Fragment {
RecyclerView recyclerPoslovi;
List<Posao> posloviD;
String nazivPoslodavca;
Intent intent;
public MojPosaoAdapter mojiPosloviAdapter;
private MojPosaoAdapter.MojPosaoClickListener listener;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_moji_poslovi, container, false);
Note: That mentioned fragment is a part of navmenu!

Android - setVisibility not changing visibility of RelativeLayout

I am trying to manipulate the visibility of RelativeLayout on a certain click event, using the visibility attribute.
After adding event handlers to each list item, I can check that the visibility status is changing, but in the Android emulator, the screen doesn't change at all (and I have tested it with visibility="visible" in the XML to make sure that it would show up).
Here's the code for the click handler:
someHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LayoutInflater layoutSeed = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View baseView = layoutSeed.inflate(R.layout.activity_listings, null, false);
RelativeLayout popup = (RelativeLayout) baseView.findViewById(R.id.popupContainer);
Log.d("Tag1",Integer.toString(popup.getVisibility()));
popup.setVisibility(View.VISIBLE);
Log.d("Tag2",Integer.toString(popup.getVisibility()));
}
});
Logcat shows the status change. I've also tried to invalidate() and postInvalidate() on both baseView and popup, as well as popup.bringToFront() and the combinations of these and so far nothing's working.
Any suggestions or possible routes to investigate?
If the RelativeLayout you are trying to change visibility is already in the screen, you don't need to inflate it again. Please make a reference to already inflated one and change its visibility
holder.relativeLayout.setVisibility(View.GONE);
Gone will remove the view from your layout. Use Invisible instead of gone.
when you click on button your View is replace by button's OnClick(View v) method.
so you just write down
v.popup(View.GONE)
Look at this line of code:
View baseView = layoutSeed.inflate(R.layout.activity_listings, null, false);
RelativeLayout popup = (RelativeLayout) baseView.findViewById(R.id.popupContainer);
Log.d("Tag1",Integer.toString(popup.getVisibility()));
Actually, you're trying to create a new baseView and set it gone. If you want to set the row item gone, you should remove it from your adapter temporary instead such as (if you set itemView to gone, you should be careful with the resuing view of the adapter):
removeItemAt(getAdapterPosition())
notifyDataRemoved(getAdapterPosition())

Portrait layout doesnt work when activity starts in landscape

This is a scaled down version of the actual problem. To recreate the difficulty I am facing.
I have taken the example from the official website developer.android.com to cite my problem.
Building a Flexible UI
MainActivity has 2 layouts. One is for the default(portrait in small screen devices) layout in the layout folder. The other layout for both large-screen and landscape mode, kept in layout-large and layout-land folder.
Default layout for activity_main.xml contains only one FrameLayout (R.id.fragment_container) in which I add and replace 2 fragments that I create, dynamically.
The other layout is same for both the layout-land and layout-large folders. It has 2 static fragments [R.id.headlines_fragment - to display a list of headlines] and [R.id.article_fragment - to display the details when headlines are selected]. Horizontally placed. One on the left to show the lists and the one on the right to show details.
This is the code for MainActivity.java which controls all the fragments :
public class MainActivity extends Activity implements OnHeadLineSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_article);
if(findViewById(R.id.fragment_container) != null) {
if(savedInstanceState != null) {
return;
}
HeadlinesFragment firstFragment = new HeadlinesFragment();
firstFragment.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).commit();
}
}
#Override
public void onArticleSelected(int position) {
ArticleFragment articleFrag = (ArticleFragment) getFragmentManager().findFragmentById(R.id.article_fragment);
if(articleFrag != null && articleFrag.isVisible()) {
articleFrag.updateArticleView(position);
} else {
articleFrag = new ArticleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction().replace(R.id.fragment_container, articleFrag);
transaction.addToBackStack(null);
transaction.commit();
}
}
}
As soon as the activity is started, I check if fragment_container that is the FrameLayout is present or not. If it is not present, then the layout with the 2 fragments has been loaded. Hence no need to add the fragments dynamicaly as they are already present.
Otherwise, I check if the savedInstanceState is null or not. If null, then I create a new HeadlinesFragment and add it to the frame. If it is not null, then it means that the activity has already been created previously, and hence the HeadlinesFragment must have been added already. No need to add it again. So, return.
And onArticleSelected() method replaces the existing fragment in the frame with the ArticleFragment, or if in the other layout, it simply updates the fragment as it is already present. It is called from the HeadlinesFragment when an item is selected.
Now, this all works perfectly well if we enter the activity in portrait mode and then change the orientation. No problem. Flawless.
But if we enter the activity in the landscape mode, as soon as I change the orientation to the portrait mode, a blank screen is shown.
The reason being, the onCreate() is called, and the savedInstanceState returns as not null. Hence, the HeadlinesFragment is not created and added to the frame.
And yes, if I remove that check, then the app works fine, but that will mean that a new HeadlinesFragment is created and added to the frame each time and gets stacked on top of eachother. Which is not at all desirable.
I cannot implement this by just finding out the orientation and applying the appropriate layout. Because, in large-screen devices, even if it is in portrait mode, it is supposed to show both the fragments at once.
I have tried many convoluted logic. But nothing seems to work. Any help is appreciated.
Entering activity in portrait mode
1> List Items are shown.
2> Clicking items replaces the fragment with the ArticleFragment (details).
3> Changing the orientation, shows both side by side. Everything works.
--->
Entering activity in landscape mode
1> Both the list and details are shown. Everything works.
2> But as soon as the orientation changes, you get the blank screen. As Headlines fragment is not created and added.
-->
It would be really helpful if someone could guide me as to how I can solve this problem. And as the actual project is huge, and this logic has already been implemented, a drastic change in logic is not an option anymore as that will mean re writting thousands of lines of code. Thank you. :)
Ok. I got the problem. The problem is we are using Fragments in xml layouts in large devices.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.android.fragments.ArticleFragment"
android:id="#+id/article_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
So android is trying to catch the Fragments in savedInstanceState in MainActivity. When screen rotates, system tries to restore the above Fragments even though different layout loads in potrait mode. And so system considers that the article_fragment is also available on the right side and it tries to update it on click on the Headline.
So, What's the solution ?
I have changed a little code in MainActivity and nothing else :-)
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
/*if (savedInstanceState != null) {
return;
}*/
// Create an instance of ExampleFragment
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
So what I have done just I told the system that I don't want any thing restored by using super.onCreate(null); so its restoring nothing now.
About the blank screen you are getting
Whenever you start activity in landscape mode. It loads large display by default. Without entering into if satement. Because it can't get fragment_container in landscape mode. And then you rotate screen to load portrait layout and system gets savedInstanceState != null and it returns without loading HeadlinesFragment. So you get bank screen.
So I have commented If statement as you can notice.
/*if (savedInstanceState != null) {
return;
}*/
So now It load everything correctly.
No issue
Download the code sample from this Developer site and modify it according to your needs.
Build Dynamic UI with fragments
Its super and reliable code.
I'm sure there are reasons why the Fragment was rendered correctly in Portrait -> Landscape and not in the reverse but one thing is very clear about the Activity lifecycle
Called when the activity is starting. This is where most
initialization should go: calling setContentView(int) to inflate the
activity's UI, using findViewById(int) to programmatically interact
with widgets in the UI, calling managedQuery(android.net.Uri,
String[], String, String[], String) to retrieve cursors for data
being displayed, etc.
Note the part that says This is where most initialization should go. By exiting after checking that savedInstanceState is null, you're leaving it up to the super class to restore your Fragment which is not a good idea considering the previous view was destroyed.
My advice, inspect the content of savedInstanceState instead of just checking if it is null. Ensure that it contains enough data to restore your previous state, if not initialize your Fragment.
The best practices with Fragments involve implementing all necessary methods to monitor the state.

How to properly apply and customize a global navigation drawer with Activities

I am working on a big app that has recently adapted the drawer navigation style and now I'm trying to customize some of the elements.
Because of its great size and complexity it was decided to adapt the navigation drawer to Activities and Fragment Activites instead of Fragments as the extended standard use.
For that I created a base Drawer activity called NavDrawer, which is inherited/extended by all of those activities that need to navigate with the Drawer. Every Activity that extends NavDrawer Activity calls NavDrawer onCreate method by calling super.onCreate(savedInstanceState, R.activity_layout) adding its layout_id instead of executing setContentView(R.layout_id).
This base Activity also handles all the intent calls to the other different activities whenever the user clicks on one of the sections/textviews.
I managed to make it work pretty well so far but I'm facing now a weird issue when customizing the Typeface of the TextViews inside the drawer. First time it is launched the app, I can see all the links without the proper style, but only after selecting one of the sections of the drawer, navigating to it and opening again the drawer, I see the textviews properly formated with my custom font.
I have been struggling with it for a few days already, and I am sure it has to be a stupid rookie mistake but I can´t figure it out what it is.
This is the NavDrawer class OnCreate method:
protected void onCreate(Bundle savedInstanceState, int resLayoutID) {
super.onCreate(savedInstanceState);
setContentView(resLayoutID);
AC = (ApplicationController)getApplicationContext();
mModel = AC.getModel();
//Setting up controls for the navigation drawer
if(AC.getModel().hasRatedApp() != null && AC.getModel().hasRatedApp()){
mLinksTitles = getResources().getStringArray(R.array.menu_links_has_rated);
}
else
mLinksTitles = getResources().getStringArray(R.array.menu_links_has_not_rated);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerContainer = (LinearLayout) findViewById(R.id.left_drawer_cont);
mDrawerList = (ListView) findViewById(R.id.menu_links);
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(AC, R.layout.drawer_list_item, mLinksTitles){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Typeface mFaceR = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/Lato-Regular.ttf");
View v = super.getView(position, convertView, parent);
((TextView) v).setTypeface(Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/Lato-Light.ttf"));
return v;
}
});
I would really appreciate any help or code you could provide me since I´m still quite new in Android development.
Finally I just found out what was going on, actually I set by mistake another adapter for my mDrawerList later in the code. As I said, stupid rookie mistake, but the code above still worked for me and hope it can help other people to customize their Navigation Drawers too.

How to get information from my Android Fragment to MyActivity.java

I'm trying to learn to create an Android fragment to implement an amount insert box which I can reuse throughout my application. So I create a simple xml file which has some EditText boxes. I then created the associated java file called AmountFragment.java:
public class AmountFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.amount_fragment, container, false);
return view;
}
}
I then use this fragment in another xml file:
<fragment
android:name="com.example.android.ui.widget.AmountFragment"
android:id="#+id/transaction_amount"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
This works fine so far. It shows the fragment fine and I can insert numbers in it. I now want to be able to get the inserted text in the mainActivity. So I read this page on Fragments from the Android docs, but I'm totally lost. The code they show makes no sense at all to me. I need to define an interface, but I have no clue what I have to do with it. I tried simply copy-pasting it over, but I get an InflateException. Since I don't even know what's going on I have no clue where to look for a solution.
So my question: can anybody give me some pointers on how to interface this fragment with the Activity in which I use it?
Try the following code.
In MainActivity.java add
public void getMessage(Object obj) {
Log.d("My App", "Look at my object " + obj.toString();
}
That will get objects from your AmountFragment, then in your AmountFragment write:
String anyObject = "Yay something";
((MainActivity)getActivity()).getMessage(anyObject);
What's happening here is that getActivity() will get the instance of the Activity which contains the fragment, then you cast it to your activity, MainActivity, and call the receiver method you wrote for it.

Categories