I have been working on an app that adds views programmatically to a linear layout.
The problem is if I add too many views it will go off the screen.
I would like to know how to check if a certain child has hit the end of the same view group so I could add it into another layout (a linear layout below the first one) before it "flows" and go off the screen. How might I accomplish this?
Rather than reinvent the wheel yourself, I suggest that you check out the FlexboxLayout project by Google: https://github.com/google/flexbox-layout
A FlexboxLayout will automatically give you the behavior you're describing, plus the potential for much more.
Well, there are a good number of ways you could implement this in android other than going through this hustle. What ever you are trying to do at the moment may fall under one of the following cases.
Creating views programmatically most likely means you have a dynamic data set probably from an external source.
Your dataset is limited or static but just more than the average screen can display.
if any of the above apple then you are better off using a ListView or RecyclerView (Recommended). That way your data is full displayed as a scroll-able list and you don't have to worry about some items or views not showing or going of the screen. This can range from simple string list to complex nested views.
This will be very efficient as it will automatically handle optimization and usage of memory as well as performance.
Let's assume we have a fragment and somewhere along its contents we have a part that is supposed to display X views.
We don't know the X number since it is not fixed.
Each of the X views can completely different. E.g.
Separator
TextView
Separator
Linear View with children
Separator
TextView
Separator etc
you get the idea.
So I was thinking
1) should this be build as some kind of custom component? How would I pass the data?
2) I originally thought this should be an inner fragment but then I thought that I don't care about the activity lifecycle about this.
3) Another approach is to just have a small function inside my fragment to add these programmatically but then how could I make this reusable?
What is the best strategy on these kind of designs?
I have been digging around in the search view source code for quite sometime now trying to understand how exactly does the search view even have a user interface to be rendered. First of all here is the source code:
SearchView source code
So what I don't understand is how does the user interface element of the search view even get rendered when the search view doesn't even have any onDraw() method. All that I can see is responsible for the display element is a bunch of view at the start which are in the constructor, the SearchView gets a reference to and change the background and set the image of these view. If all that I can see was done is getting references to some views and changing the background as well as the image without having it within the proper view hierarchy then how exactly does it even get rendered?
I understand what you are probably wondering why do I even need to understand this. Well I want to understand this so I can create my own custom search view. Since I only need like 2 function on my search view I figure it would be a lot better to make one that suits my need instead of the thousand of lines of code in the source one. Plus, I want to create one that I know I will understand how to use not the complex default one.
I'm trying to write some automation scripts for an app I have. I've done the tutorial on Robotium's site and have a basic understanding on how I can automation. However from what I can tell regarding the app I'm testing is by using the android hierarchy viewer I see that all of the views have no ids that were explicitly defined.
As you can see from the screen capture there are views upon nested views. The IDs for them read like 0x17e0 or 0x17de. How can I reference these, specifically, in a robotium script? The end result is I'm trying to get it to fire a click even on one of the Text Switcher views. So far I've only been able to make it work if I give it a pixel point to go to, or if I give it the text that appears in the button (but the text is dynamic and would make for a poor test).
Do I have to use the getCurrentViews() to filter down to the text switchers? Or do I have to figure out a way to traverse the entire tree going from FrameLayout>RelativeLayout>FrameLayout>LinearLayout>TextSwitcher ?
If I have to traverse the entire tree how do I get view upon view upon view?
While I couldn't get the ViewGroup() and getChildAt() methods to work for me I ended up doing something different:
// Grabbing all the LinearLayout views found under view with with id of 'content'
ArrayList<LinearLayout> linearLayouts = solo.getCurrentViews(LinearLayout.class, solo.getView(R.id.content));
// The 4th item in the linearLayouts list is the one I need
View pickerList = linearLayouts.get(3);
// Grabbing the buttons in the pickerList
ArrayList<TextSwitcher> buttons = solo.getCurrentViews(TextSwitcher.class,pickerList);
// Now I can click on the buttons
solo.clickOnView(buttons.get(0));
I will say this is slow. It takes about 10 seconds for the first button click to fire. But once it goes it flys.
I would vote to say you really probably want to get some IDs added somehwere in the hierarchy, it is a one line change that will make your life a hell of a lot easier.
But i am not without help if for some reason you cannot get this done, to do this you are going to have to walk the entire to get to the view you want.
Getting the top level view, you will be able to cast it into a ViewGroup. ViewGroups have a method called getChildAt() which you can then use to get a child at a given index, the index is 0 based and will match what you see in the hierarchy viewer so you can chain together theses commands to get to the view you want to interact with.
I have not used Robodtium very much, but i know that AndroidViewClient does exactly what you want. Here is a code snippet that dumps Id of the home view:
ViewClient(*ViewClient.connectToDeviceOrExit()).traverse(transform=ViewClient.TRAVERSE_CIT)
Here is the result dump:
com.android.launcher2.CellLayout id/cell3 None
com.android.launcher2.ShortcutAndWidgetContainer NO_ID None
com.android.launcher2.BubbleTextView NO_ID Email
com.android.launcher2.LauncherAppWidgetHostView NO_ID None
android.widget.AnalogClock id/0x7f0f0014 None
com.android.launcher2.BubbleTextView NO_ID Camera
com.android.launcher2.BubbleTextView NO_ID Settings
com.android.launcher2.BubbleTextView NO_ID Gallery
com.android.launcher2.LauncherAppWidgetHostView NO_ID None
android.widget.LinearLayout id/0x7f080167 None
First off my background: I'm new to Java coming over from Ruby. If that helps.
I'm confused about how layout params work. I'm following a basic Hello World introduction to creating an Android App. Step 1, extend the Activity class, and the onCreate() method to access the XML layout. Ok I get that.
Then I create a layout (say a RelativeLayout) in the Main.XML. So this is making use of the RelativeLayout class which extends the ViewGroup class, ok so far. Then lets say I create a button inside this. This is where my question starts. If I look at the example I am following I see attributes being assigned to the button that belong to the RelativeLayout class (i.e: android:layout_alignParentRight="true"). These seem to be the layout params. But why does this work? The button class seems to inherit from the View class. Why can a button object accept attributes for the RelativeLayout object? Maybe my Ruby programming is confusing me..
Thanks!
Update: For posterity sake: thank you to Slothsberry for pointing out the XML Layouts link, which seems to describe the answer clearly in 2 sections the section on "Attributes" and on "Layout Paramters". The attributes section reads:
Every View and ViewGroup object supports their own variety of XML
attributes. Some attributes are specific to a View object (for
example, TextView supports the textSize attribute), but these
attributes are also inherited by any View objects that may extend this
class. Some are common to all View objects, because they are inherited
from the root View class (like the id attribute). And, other
attributes are considered "layout parameters," which are attributes
that describe certain layout orientations of the View object, as
defined by that object's parent ViewGroup object.
The layout parameters section though is perhaps the section that really answers this question. Where it states:
Every ViewGroup class implements a nested class that extends
ViewGroup.LayoutParams. This subclass contains property types that
define the size and position for each child view, as appropriate for
the view group. As you can see in figure 1, the parent view group
defines layout parameters for each child view (including the child
view group).
They give a nice diagram as well. It seems that a beginning programmer needs to recognize that while Java classes are referenced, the XML acts more like a CSS sheet and that attributes are first computed in a nested fashion before being computed and carried over to their Java class counterparts. That's my current understanding anyways :)
Layout parameters do not strictly mirror object inheritence (as you have noticed). The reason is that there are two parts of layout: configuring a view, and parametrizing a view's parent using that view as an argument.
So parameters like android:layout_below will be ignored if the parent layout is not a RelativeLayout. It might make sense from an OOP perspective to put that parameter in the RelativeLayout object. But that is how you would do it in the java code.
In the XML code, it takes the approach that the information about the child is contained in the child. layout parameters that require a parent that is not present will be ignored when the layout is inflated. Its a nice system android uses to make the XML more readable and portable. And it is not strictly referring to the class package structure, but rather the intuitive way humans think about placing things in a layout.
All layout elements in android inherit from View, although many indirectly.
The generic View class has properties (attributes) appropriate for ANY visible layout element. for the root layout, some properties such as Layout Gravity, Layout dimensions, etc. are set by the system (in most cases I believe).
If my root layout is some linear layout, Android will allow me to have a relative layout be a child in the root. Android will let me set various layout properties on the nested element, in order to control how it renders. This works the same for Button, and any other Android layout.
If you don't care about a particular property, don't set it. They are present to allow you control over the screens of your app. Look into XML Layouts or Hello Views to get you started on the details.
you are a little bit confused, that layout param doesn't own a particular XML object . If you put it in one child XML XXXView or XXXLAyout , it will understand that its Right side must be in the same place than parent right.
Then if you don't create the layout params for that child , the child would try to inherit ones of its parent's.
Layout
Layout is a two pass process: a measure pass and a layout pass. The measuring pass is implemented in measure(int, int) and is a top-down traversal of the view tree. Each view pushes dimension specifications down the tree during the recursion. At the end of the measure pass, every view has stored its measurements. The second pass happens in layout(int, int, int, int) and is also top-down. During this pass each parent is responsible for positioning all of its children using the sizes computed in the measure pass.
When a view's measure() method returns, its getMeasuredWidth() and getMeasuredHeight() values must be set, along with those for all of that view's descendants. A view's measured width and measured height values must respect the constraints imposed by the view's parents. This guarantees that at the end of the measure pass, all parents accept all of their children's measurements. A parent view may call measure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small.
The measure pass uses two classes to communicate dimensions. The View.MeasureSpec class is used by views to tell their parents how they want to be measured and positioned. The base LayoutParams class just describes how big the view wants to be for both width and height. For each dimension, it can specify one of:
an exact number
MATCH_PARENT, which means the view wants to be as big as its parent
(minus padding)
WRAP_CONTENT, which means that the view wants to be just big enough
to enclose its content (plus padding).
There are subclasses of LayoutParams for different subclasses of ViewGroup. For example, AbsoluteLayout has its own subclass of LayoutParams which adds an X and Y value.
MeasureSpecs are used to push requirements down the tree from parent to child. A MeasureSpec can be in one of three modes:
UNSPECIFIED: This is used by a parent to determine the desired
dimension of a child view. For example, a LinearLayout may call
measure() on its child with the height set to UNSPECIFIED and a width
of EXACTLY 240 to find out how tall the child view wants to be given
a width of 240 pixels.
EXACTLY: This is used by the parent to impose an exact size on the
child. The child must use this size, and guarantee that all of its
descendants will fit within this size.
AT_MOST: This is used by the parent to impose a maximum size on the
child. The child must guarantee that it and all of its descendants
will fit within this size.
To initiate a layout, call requestLayout(). This method is typically called by a view on itself when it believes that is can no longer fit within its current bounds.