Adding items to the ScrollView dynamically make it doesn't scroll - android

I have a simple layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:padding="15dp">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/scrollLayout">
</LinearLayout>
</ScrollView>
</RelativeLayout>
Now, I inflate the outer RelativeLayout to retrieve the inner LinearLayout to put items in it.
RelativeLayout relative = (RelativeLayout) LayoutInflater.from(activity).inflate(R.layout.gradient_pick_view, null);
LinearLayout view = (LinearLayout) relative.findViewById(R.id.scrollLayout);
After that I created a method to add some buttons to it:
for(int i=0;i<10;i++){
LinearLayout wrapper = (LinearLayout) LayoutInflater.from(activity).inflate(R.layout.button_wrapper, null);
Button button = (Button)wrapper .findViewById(R.id.button);
view.addView(layout);
}
Everything works fine, but it doesn't scroll.
What am I doing wrong here?
Here's the screenshot (displaying 7 of 10 buttons):
I forgot to mention - I'm using a MaterialDialog library and add this RelativeLayout as a custom view to a dialog.

Try to set the following attribute to your scrollview,
android:fillViewport="true"
above attribute is used to make your scrollview to use entire screen of your application.

I had a false parameter passed to a customView in a MaterialDialog.
dialog = new MaterialDialog.Builder(activity)
.title(R.string.about)
.customView(view, true)
.positiveText(R.string.changing_fragments)
.show();
As doc says:
If wrapInScrollView is true, then the library will place your custom view inside of a ScrollView for you. This allows users to scroll your custom view if necessary (small screens, long content, etc.). However, there are cases when you don't want that behavior. This mostly consists of cases when you'd have a ScrollView in your custom layout, including ListViews, RecyclerViews, WebViews, GridViews, etc. The sample project contains examples of using both true and false for this parameter.
Now it's working.

Related

ImageButton displays differently when created dynamically

I have a GridLayout-based View to which I am dynamically adding several ImageButtons. I'm trying to understand why the ImageButtons are styled correctly when I inflate them from a layout xml file, but not when I create them using the ImageButton constructor directly.
The GridLayout and ImageButtons were previously both defined in the same layout .xml file (and rendered as expected):
<ScrollView
style="#style/my_list_style"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="12dp">
<GridLayout
android:id="#+id/my_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<!-- These ImageButtons are being converted to dynamic. -->
<ImageButton
style="#style/my_button_style"
android:src="#drawable/image1" />
<ImageButton
style="#style/my_button_style"
android:src="#drawable/image2" />
</GridLayout>
</LinearLayout>
</ScrollView>
To convert the ImageButtons to dynamic, I first removed them from the layout file and used code like the following to add them at runtime:
ImageButton imageButton = new ImageButton(context, null, R.style.my_button_style);
imageButton.setImageResource(R.drawable.image1);
parent.addView(imageButton);
But the buttons failed to render properly; they are not centered, and their sizes do not appear to be correct/uniform.
I then tried creating a new layout file, containing nothing but the ImageButton and its style:
<ImageButton
style="#style/my_button_style"/>
When I inflate this layout into the GridView at runtime, everything looks as expected:
LayoutInflater inflater = LayoutInflater.from(context);
ImageButton imageButton = (ImageButton) inflater.inflate(
R.layout.my_button_layout, parent, false);
imageButton.setImageResource(R.drawable.image1);
parent.addView(imageButton);
Why does inflating the view with LayoutInflator give different results than creating the button directly from its constructor?
Because when you create ImageButton manually, you do not specify its parent, hence it doesn't know the layout params of its parent and can't be laid out as you expect.
On the other hand, when you inflate it via LayoutInflater, you are specifying the parent. Then correct layout params are being passed to children. That's why you see difference.
Have a look at detailed article by Dave Smith.

ListView in a ScrollView Dilemma - How has this app managed to do it?

So basically you can't place a ListView in a ScrollView because the Scrolling ability clashes in both layouts. When I tried to do it, the ListView becomes completely useless and many other problems arise.
How has Facebook done it?
As you can see, the work section is a ListView and it's also a Scrollable layout so that the user can scroll down to view the Education section, which is also a ListView.
My code:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff"
android:layout_marginBottom="40dp">
<!-- More layouts -->
<ListView
android:id="#+id/work_list"
android:layout_below="#+id/recentpic"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</ScrollView >
I do not want a ListView Scroll bar
Therefore the scrolling dilemma is completely removed from the equation. Even when I disable the scroll bars, the problem persists.
Solution that I have in mind:
Generating the XML rows (Each Workplace of the ListView) and injecting it to the layout and avoiding the use of ListViews, similar to HTML Code Generation using Javascript.
What method do you think Facebook has used in their android app to get this done and what changes should I make to my code? :)
Have you tried using NestedScrollView? I think it's a NestedScrollView which contains a ListView and the whole thing is enclosed in a ScrollView. This link might help:
http://ivankocijan.xyz/android-nestedscrollview/
Okay so I managed to code my own idea I mentioned. It's a very 'sexy' code and it gets the job done :D
Here you go, guys. I hope it helps someone :)
So basically I'm inflating a Parent Layout with multiple Child Layouts dynamically and completely getting rid of ListViews in the view. Which makes is very simple to use it with a ScrollView and forget about that dilemma.
Parent Layout:
<RelativeLayout
android:id="#+id/work_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
Child Layout - work_single_item.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff">
<ImageView
android:id="#+id/work_pic"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:src="#mipmap/image_placeholder"/>
</RelativeLayout>
Coded the following lines in the OnCreate function of the Parent Layout.
RelativeLayout parent = (RelativeLayout) findViewById(R.id.work_list);
//array containing all children ids
ArrayList<Integer> children = new ArrayList<>();
//adding 10 children to the parent
for(int i=0;i<10;i++) {
RelativeLayout child = new RelativeLayout(this);
View tempchild = getLayoutInflater().inflate(R.layout.work_single_item, null);
child.addView(tempchild);
child.setId(i); //setting an id for the child
children.add(i); //adding the child's id to the list
if(i!=0) //if it isn't the 1st child, stack them below one another, since the 1st child does not have a child to stack below
{
RelativeLayout.LayoutParams params
= new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, children.get(i - 1)); //stack it below the previous child
child.setLayoutParams(params);
}
parent.addView(child); //add the new child
}

Dynamically add and move Views in ScrollView

I have the following layout:
<HorizontalScrollView
android:id="#+id/scrollableContents"
android:layout_above="#id/getting_started_buttons_container"
android:layout_below="#id/getting_started_title_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<FrameLayout
android:id="#+id/getting_started_keywords_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
</FrameLayout>
</HorizontalScrollView>
In which i dynamically add views using a for loop in a container, i,m using translation to move them to right
index = 0;
for (Word word : wordList) { //wordList size is 15 or more
index++;
view = new MyView(this, null);
view.setTranslationX(index * 150);
container.addView(view);
container.invalidate();
scrollView.requestLayout();
scrollView.invalidate();
}
My scrollView does not extend over the screen since it has the initial empty view. I need to see all views. Can anybody help me? I need a way to update scrollView to a width that contains all my elements
EDIT: I want to achieve something like these with a dynamically number of circles, which must extend in scrollView if there is no room on the screen. LinearLayout is not a solution....
replace RelativeLayout with horizontal LinearLayout
you used RelativeLayout as parent view. Then you will need to use LayoutParam to add Rules for setting position like toRightOf() and alignParentTop.
If you don't add rules for your views, your views will be overlapped in same place (Top and Left)
So just use LinearLayout with orientation to be easy.
Thanks. Hope this will help you.

Adding new widget controls dynamically to an existing layout

i've seen this question added on the stack but the information hasn't been helpful or successful yet, so i remain quite not sure.
The gist of what I'm trying to do:
I have a layout defined in xml, some_details_view.xml for example.
setContentView(R.layout.some_details_view);
It has a bunch of text views laid out using a parent relative layout, a linear header layout, a linear footer layout, a middle scroll layout that contains a relative layout that hold some label - value type of text views.
And at the bottom of the scroll view relative layout, I currently placed a frame layout as a place holder.
On create of the corresponding activity, I set text in respective text views with data handed over from previous activity; basic stuff.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white" >
<LinearLayout
android:id="#+id/header"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" >
...some header content
</LinearLayout>
<LinearLayout
android:id="#+id/footer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical" >
..some footer content
</LinearLayout>
<ScrollView
android:id="#+id/scroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/footer"
android:layout_below="#+id/header"
android:layout_margin="5dip" >
<RelativeLayout
android:layout_width="fill_parent"
android:id="#+id/relativeScroll"
android:layout_height="wrap_content" >
...text views in relative layout
<FrameLayout
android:id="#+id/placeholder"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/moreInfoValue" />
</RelativeLayout>
</ScrollView>
</RelativeLayout>
After setting up text views for the given data, I use an async task to get some additional data that I want to show as a history list type of thing at the bottom of the static form layout. There could be 0 or more items so I either add 1 or more text views or none at all.
In the post execute, which I understand to run on the main UI thread, I try to find an exiting container Layout/view group and add either a new Linear Layout to which I add new text Views, or just add the new text views directly to the existing container layout.
here's the latest thing I tried:
ViewGroup mContainer = null; //defined as member variable of activity class and instatiated in on create
mContainer = (ViewGroup)findViewById(R.id.placeholder); //set in on create
LinearLayout ll = new LinearLayout(context); //on post execute of async task
ll.setOrientation(LinearLayout.VERTICAL);
mContainer.addView(ll); //add a new linear layout to an existing container layout
//add some new text view widgets items dynamically
for(NewDisplayItem item : items)
{
TextView tv = new TextView(context);
tv.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
tv.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
tv.setText(item.getSomeText());
ll.addView(tv); //add text view to new linear layout
}
When the UI loads I don't see new items added to my layout after stepping through and watching the controls get added using the code above.
Not sure what it is but something doesn't seem right about this approach in addition to the fact that it's not working. When the activity loads up, all the static views are setup and in view. I pop up a loading dialog, step through the async task stuff and I guess expect to see the dynamic controls add to the layout one by one?
First of all textView.setWidth(int) takes as parameter the width in pixels.
Second you should also set your layout parameters on the LinearLayout you are adding.
The way you should set LayoutParams is as follows :
ll.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
the same for yout TextViews.
Ovidiu Latcu has a good answer. A good question is: is there a reason why you aren't using a ListView (which btw there ARE cases where what he's doing works better)? A ListView has a lot of mechanisms to help you keep from running out of RAM

Placing button or other widget at runtime on android app

Quick question: at runtime I do a boolean check, if it returns true I would like to have two buttons in a relative layout on my MainActivity class. If its false I want to instead have two other widgets where those buttons would be (or near enough). How do I do that?
you could also implement a ViewSwitcher where a more complicated set of buttons/widgets can be switched out very easily with a single call to
ViewSwitcher mViewSwitcher = (ViewSwitcher) findViewById(R.id.viewswitcher);
if (some_logic == true) {
mViewSwitcher.showNext();
}
Set up your XML like this and the above will switch between the two LinearLayouts:
<ViewSwitcher
android:id="#+id/viewswitcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
--- buttons, Views, whatever---
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
--- buttons, Views, whatever---
</LinearLayout>
If you have just those two alternatives put them both in your layout and hide / show the one you want. View#setVisibility()
If you want it more dynamic you can add and remove widgets programmatically. ViewGroup#addView()
Modifying a RelativeLayout during runtime is quite complicated since you need to set all those layout parameters so you could add a simple layout like a FrameLayout in the place where the buttons should go and put them inside the frame. Has the advantage that you can setup all the relative layout parameters for the frame in xml.

Categories

Resources