Vertical layouts with dynamically generated nested fragments in Android - android

So after much ridiculous jumping through of hoops and general contortionism I convinced Android to do an elementary and often required task. That is to generate zero to any number of views with any number of different layouts and associated variables and insert them into another view so that they stack vertically.
Well almost.
Android begrudgingly agreed to include all the views after I read and modified the code from this question.
public void setPeriods(ArrayList <HashMap> periods) {
for(HashMap<String, Object> period: periods){
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
ForecastPeriod forecastPeriod = new ForecastPeriod();
childFragTrans.add(R.id.forecast_period, forecastPeriod);
childFragTrans.commit();
forecastPeriod.setTitle((String)period.get("name"));
}
}
The problem is that the views will not stack, or at least Android, as if to taunt me "stacked" them but on the Z plane so they overlap one another completely. How can this be?
<LinearLayout 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:orientation="vertical"
android:paddingTop="20dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="0dp"
tools:context="com.blah.deblah.ForecastPeriods">
<fragment
android:id="#+id/forecast_period"
android:name="com.blah.deblah.ForecastPeriod"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:layout="#layout/fragment_forecast_period" />
</LinearLayout>
How can I change (hopefully) the XML to make these guys stack vertically as they should?
Below is the XML for the fragment being inserted.
<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="wrap_content"
tools:context="com.blah.deblah.ForecastPeriod">
<TextView
android:id="#+id/period_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:fontFamily="sans-serif-bold"
android:gravity="start"
android:singleLine="true"
android:text="#string/title"
android:textColor="#cccccc"
android:textSize="24dp" />
<TextView
android:id="#+id/period_headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:layout_below="#id/period_title"
android:layout_marginTop="20dp"
android:fontFamily="sans-serif-light"
android:maxHeight="90dp"
android:gravity="left"
android:text="#string/loremipsum"
android:textColor="#cccccc"
android:textSize="24dp" />
<TextView
android:id="#+id/period_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:layout_below="#id/period_headline"
android:layout_marginTop="20dp"
android:fontFamily="sans-serif-light"
android:gravity="left"
android:text="#string/loremipsum"
android:textColor="#cccccc"
android:textSize="18dp" />
</RelativeLayout>

The reason you are having so much trouble is because your understanding of Fragments is fundamentally incorrect. Refer to this question, which I posed when I had trouble understanding them as well and greatly cleared this all up. Android simply doesn't want you to use Fragments like you are trying to, so of course it's not going to do what you expect it to.
In general, a Fragment shouldn't necessarily be a single UI component, but rather function more like an Activity that acts much more like any other UI component, thus making it much more useful. What you are trying to use a Fragment as, should really be done using a custom View or a ListView.
As an aside, you are also declaring your Fragment in your code incorrectly. You should either use the package name as the XML tag, or else a FrameLayout and insert your Fragment in the specified FrameLayout, not <fragment>

Related

Display many views efficiently in a FlexboxLayout

My goal is to efficiently display a lot of TextViews (with background) in a FlexboxLayout (or something similar).
I want to display information about actors and crew members from a movie in a kind of 'tag'-layout style
How the layout looks like (one of the FlexboxLayouts is marked)
I inflate the TextViews dynamically via LayoutInflater into a FlexboxLayout. The problem is of course that with a lot of data (which means a lot of views, sometimes 30 or more in over 20 Flexbox-Layouts) the creation time of my fragment/activity increases and the activtiy takes longer to open.
The TextView I inflate:
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tag_name"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_margin="5dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:gravity="center_vertical"
android:background="#drawable/bg_tag"
android:textColor="?android:textColorSecondary"
android:text="#string/placeholder" />
My container layout (TextViews get inflated into the FlexboxLayout #+id/fxl_names):
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/txt_names"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/colorOnBackground"
android:padding="5dp"
android:textSize="16sp"
android:textStyle="bold"
android:text="test" />
//TextViews get inflated into this FlexboxLayout
<com.google.android.flexbox.FlexboxLayout
android:id="#+id/fxl_names"
app:flexWrap="wrap"
android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/view_more"
android:visibility="gone"
android:layout_margin="0dp"
android:text="Show all"
style="#style/Widget.MaterialComponents.Button.TextButton.Dialog" />
</LinearLayout>
Thank you for any help/advice on optimizing this layout!
When you had to inflate a lot of views dynamically, you should use something called ViewHolder to ensure the optimization of the inflate view action.
For your problem may you had to use a RecyclerView instead a FlexBoxLayout, the best solution in my opinion. And a FlexBoxLayoutManager to organize your views.
There is a example in the Android FlexBoxLayout repository

Android button does not trigger when in different order in XML file

not urgent as I have a work around, however I would really like to understand whether there is a reason for a behaviour I observe when i make the changes below.
I have a simple layout with an EditText and a Button in an XML file.
It displays fine, and as the code below it works fine (triggering onClick)
<RelativeLayout android:id="#+id/group"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<EditText android:id="#+id/Topic" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_toLeftOf="#+id/AddTopic"
android:layout_alignParentLeft="true" android:ems="10" />
<Button android:id="#+id/AddTopic"
android:layout_alignParentRight="true" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_weight="1"
android:onClick="onClick" android:textSize="10dp" android:text="Add Topic" />
</RelativeLayout>
However, if I flip the objects around, as below, the button does not trigger - onClick does not run and nothing happens.
<RelativeLayout android:id="#+id/group"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<Button android:id="#+id/AddTopic"
android:layout_alignParentRight="true" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_weight="1"
android:onClick="onClick" android:textSize="10dp" android:text="Add Topic" />
<EditText android:id="#+id/Topic" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_toLeftOf="#+id/AddTopic"
android:layout_alignParentLeft="true" android:ems="10" />
</RelativeLayout>
I might be missing something really obvious here, and as I say it doesn't matter in the sense it works in the first structure, but it does matter in the sense I would really like to know why. Any ideas appreciated.
Combining the information posted in the comments, the likely reason is the fact that you mistakenly use #+id/ when referring to other objects, instead of #id/. Specificly EditText contains android:layout_toLeftOf="#+id/AddTopic". The + sign should only be used when introducing new ids.
In the first example it is not harmful for the listener, since the button is declared after the EditText and #+id/ works as should, but in your second example the id of the button might be overriden when you declare the EditText.
TL;DR: in EditTextreplace android:layout_toLeftOf="#+id/AddTopic" with android:layout_toLeftOf="#id/AddTopic". Do this even if you use your "work around".

UI Layout Issues

First let me attempt to layout what I am trying to accomplish here.
EditText
EditText SearchButton
ListView (search result. there can be only one, ListView with adapter and height of wrap_content seems to work for this, there is a button to add the result to the ListView below. Once the add button is clicked this ListView collapses, which is exactly what I am after)
TextView (label for objects added)
ListView (list of objects added, again I'm using an adapter for the list row layout)
SaveButton
I was going to paste the code that I have but there is just too much to go through. The issues I am having are with the ListViews. Basically, the ListView that contains the objects added will end up pushing the SaveButton off of the screen. I have tried a ton of solutions laid out on this and many other sites but they just don't seem to work right.
Basically, I want the SaveButton to always be at the bottom and I don't want it to get pushed off the screen when the ListView gets too big. The only solution I have found to "work" was to explicitly set the height of the ListViews. However, this causes problems when going from tablet to phone (Nexus7 & Galaxy S3). I thought that using dip for sizes would prevent this from happening but apparently not.
If anyone has a good strategy for creating this type of layout that would be great. Or even a good resource for learning how to use Android's clunky UI system (it really leaves a bit to be desired).
Edit: here is my attempt at using a RelativeLayout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/main_background"
android:orientation="vertical" >
<EditText
android:id="#+id/plan_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:ems="10"
android:hint="#string/plan_name_hint"
android:textColor="#color/text_color" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/object_search_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/plan_name"
android:ems="10"
android:hint="#string/search_objects_text"
android:textColor="#color/text_color" >
</EditText>
<Button
android:id="#+id/objects_search_button"
style="#style/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/object_search_text"
android:layout_below="#id/plan_name"
android:layout_alignParentRight="true"
android:background="#drawable/black_button"
android:text="#string/search_objects_button_label" />
<ListView
android:id="#+id/search_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/object_search_text"
android:background="#color/main_background"
android:textColor="#color/text_color" >
</ListView>
<TextView
android:id="#+id/objects_list_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/search_result"
android:paddingBottom="8dip"
android:paddingLeft="8dip"
android:text="#string/plan_objects_list_label"
android:textColor="#color/text_color"
android:textSize="22sp"
android:textStyle="bold" />
<ListView
android:id="#+id/plan_objects"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/objects_list_label"
android:background="#color/main_background"
android:textColor="#color/text_color" >
</ListView>
<Button
android:id="#+id/save_plan_button"
style="#style/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#drawable/black_button"
android:paddingLeft="8dip"
android:text="#string/save_button_label" />
If you think the Android UI system is clunky, you obviously haven't tried to understand it. For most things its extremely well designed.
If you want a certain view (or views) to always be at the bottom, then you want to make your screen a RelativeLayout and put android:layout_alignParentBottom="true" on those element(s). Then add android:layout_above="id" on whatever you want to be above them, where id is the id of the element you want at the bottom.
Make the SaveButton and ListView at the same hierarchy level. e.g if your parent layout is RelativeLayout in your SaveButton add this property android:layout_alignParentBottom="true"
It looks like the only real solution here is to use explicit sizes for the list views and plan accordingly for different screen sizes (i.e. create different layouts for different screens and outlined here.). I was hoping for something a little more generic. Oh well.

Easier way to create and maintain many layouts

I have got an application that is essentially a giant calculator. Within this application it has a total of 75 unique equations and each one has different number of variables and displayed results. I currently have a sliding drawer implemented with the list of the equations of them to choose from and when they click on it, I have a fragment area to put the screen for calculating it. I am currently just implementing a fragment activity for each calculation along with a layout for each one. Does anyone know what best practice is for accomplishing something with this many screens? Do I accomplish them by creating the layout on the fly in the activity? Do I keep it how it is? I am just trying to figure out if the tedious work I am doing with this can be accomplished in an easier manner (I know I have to create the activities to do the work) .
EDIT
The layouts vary in complexity depending on the calcuation. Some of them are to the nth entry from the user and requires a gridview while others will just be simple like example below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=blah blah
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="DCDCDC"
android:orientation="horizontal" >
<EditText
android:id="#+id/etTempInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_below="#+id/tvTempInputLabel"
android:ems="10"
android:inputType="numberSigned" >
<requestFocus />
</EditText>
<TextView
android:id="#+id/tvTempInputLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="10dp"
android:text="Medium_Text"
android:textAppearance="?androd:attr/textAppearanceMedium" >
</TextView>
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/etTempInput"
android:layout_toRightOf="#+id/etTempInput" />
<TextView
android:id="#+id/tvTempResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/etTempInput"
android:layout_marginTop="22dp"
android:text="Medium_Text"
android:textAppearance="?androd:attr/textAppearanceMedium" >
</TextView>
<Button
android:id="#+id/btnTempCalc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tvTempResult"
android:text="Calculate" />
</RelativeLayout>
really hard without seeing the layouts, but it sounds as building up the layouts dynamically ( perhaps from building-blocks in xml ) could tidy things up
The answer I came to with this is to just create each page by itself as there is no consistency between the pages. I looked at several options but none of them met my needs. So look out 75 layouts and code files here I come.

Help Arranging TextView objects on screen in Android

I'm using textview objects to hold labels such as Score, Level etc on my game screen but they don't seem to be displayed where I want them to be. I understand about view hierarchies (parents, children) and am using the gravity tags in the XML layout file but it doesnt seem to have any effect.
Could someone just quickly provide a guide to positioning a textview object on the screen, and also linking it in the code so that its contents can be programmatically controlled (I believe this would by done via =(TextView) findViewById(r.id.resourcename))?
Many thanks
XML:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.gesture.GestureOverlayView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gestures"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gestureStrokeWidth="2.0"
android:gestureStrokeType="multiple"
android:eventsInterceptionEnabled="true">
<com.darius.android.distractions.DistractionsView
android:id="#+id/distractions_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/text"
android:text="Hello"
android:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:textColor="#88ffffff"
android:textSize="24sp"/>
<TextView
android:id="#+id/textLevel"
android:text="#string/level_count"
android:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="bottom"
android:textColor="#EB0000"
android:textSize="10sp"/>
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/concentration_bar"
android:textColor = "#EB0000"
android:textSize="10sp"
android:id="#+id/conbartext"
android:visibility="visible"
></TextView>
</RelativeLayout>
</android.gesture.GestureOverlayView>
</FrameLayout>
These are some really helpful tutorials on getting started with android layout and widgets: http://developer.android.com/resources/tutorials/views/index.html
Documentation and a guide on the layout itself is here:
http://developer.android.com/guide/topics/ui/declaring-layout.html
Common Layout Objects is a good guide to the basics of layouts. The gravity tag only has meaning in certain layout types.
Another useful tool is the Heirarchy Viewer, found in the tools folder of your Android installation. This allows you to visualize the View heirarchy of your running activity.
If you post your layout XML, and a mockup of what you are trying to accomplish, we might be able to help you accomplish it.

Categories

Resources