I'm new on android programmation. I want to achieve a simple layout with elements side by side inside a scrollview. The idea is to process a single element per time with image and text, letting the layout choose when its the right time for the carriage return, in dependence of the screen resolution. I tried every type of layout, but no one seems to be suitable for my purpose. Particulary with Relative Layout elements are overlapped, instead what I need is an spatial append. Before to try a workaroud (for example adding more element in a row inside a linear layout) i would to know if exists a more natural solution.
(source: youth-stories.com)
I create an example activity to try the solutions:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RelativeLayout container = (RelativeLayout)findViewById(R.id.container);
for(int i=0; i < 100; i++)
{
final Button button = new Button(this);
button.setText("sda"+i);
button.setId(i);
container.addView(button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
container.removeView(button);
}
});
}
}
}
<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:padding="0dp"
android:id="#+id/outer"
android:tileMode="disabled" android:gravity="top">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/background"
android:scaleType="centerCrop"/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/scrollView" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/container"></RelativeLayout>
</ScrollView>
</RelativeLayout>
From the above fig given, you can use GridView to draw UI as given. You can specify spacing between items also how many columns each row consists.
For reference check developer doc.
Check here for GridView example and doc
For the diagram shown you can go for a Grid Layout, you can customize grid layout for spacing between cells.
If it still doesn't fit your need then, my suggestion would be Linear layout with layout weights,however nested weights are a performance overhead.
http://developer.android.com/reference/android/widget/GridLayout.html
http://androidexample.com/Custom_Grid_Layout_-_Android_Example/index.php?view=article_discription&aid=76&aaid=100
Why are nested weights bad for performance? Alternatives?
Hope this help!!
Related
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.
I want to create a custom layout to reduce redundancy in the code. Currently every layoutfile has about 30 Lines of code which are identical.
My goal was to create a custom layout/view which can hold in itself children.
<BaseLayout xmlns:...>
<!-- Normal Content -->
<Button />
<Label />
</BaseLayout>
While the above xml holds most of the content, the BaseLayout is in itself an xml containing other views and functionality:
<FrameLayout xmlns:...>
<LinearLayout><!-- contains the Header--></LinearLayout>
<LinearLayout><!-- INDIVIDUAL CONTENT HERE--></LinearLayout>
<FrameLayout><!-- contains the loading screen overlay --></FrameLayout>
</FrameLayout>
So all children from the above xml should be inserted into second linear-layout. I have already succeeded into doing so. But am confronted with layout problems (match parents does not match parents and only wraps)
My approach was extending the LinearLayout with following logic:
/**
* extracting all children and adding them to the inflated base-layout
*/
#Override
protected void onFinishInflate() {
super.onFinishInflate();
View view = LayoutInflater.from(getContext()).inflate(R.layout.base_layout, null);
LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.base_layout_children);
while(0 < getChildCount())
{
View child = getChildAt(0);
LinearLayout.MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
removeViewAt(0);
linearLayout.addView(child, layoutParams);
}
this.addView(view);
}
Is there a better, cleaner approach to capsule the xml and reuse a basis layout? How do I fix the match_parent issue?
While writing this post and thinking hard how to explain best, the solution for the match_parent issue became clear. Though the question remains if there is a better approach for the whole problem.
//Solution:
this.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
//wrong:
this.addView(view);
Suppose you have two layout files. common_views.xml and layout_main.xml. You can include content of one layout file into another like this.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<include
android:id="#+id/common"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/common_views" />
<WebView
android:id="#+id/webView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/common"
>
</WebView>
</RelativeLayout>
I want to create a layout like this:
I think the ScrollView is necessary, maybe like this:
<RelativeLayout>
<RelativeLayout id="fixed">
</RelativeLayout>
<ScrollView>
<RelativeLayout>
<Button...
<ListView....
<Button...
</RelatievLayout>
</ScrollView>
</RelativeLayout>
But it seems that add a ListView inside a ScrollView is not good idea.
Any idea to make it?
BTW, there are not only Button1 and Button2 outside the listview, there are more views, so I do not think add the views as foot or head is a good idea.
This is xml code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout android:id="#+id/rlt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
</RelativeLayout>
Java code
LinearLayout llt = (LinearLayout)findViewById(R.id.rlt);
for(int i=0;i<12;i++)
{
final int k =i;
LinearLayout ll = new LinearLayout(this);
ll.setId(i);
ll.setOrientation(LinearLayout.VERTICAL);
TextView tv = new TextView(this);
tv.setText(" name:"+i);
ll.addView(tv);
ll.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
System.out.println("This is the printed text no"+k);
}
});
//ll.setBackgroundColor(Color.BLACK);
llt.addView(ll);
}
You can create your own ListView like this
First idea (not recommanded): Adding a ListView inside a ScrollView is a bad idea, because both are scrollable by default. You could use a LinearLayout instead of the ListView and create a custom onClickListener for the items.
<Scrollview>
<Button.../>
<LinearLayout>
<items.../>
</LinearLayout>
</Scrollview>
Second idea (recommanded) is to go with one ListView and create a custom Adapter extending BaseAdapter returning the Views for each row and holding the data. This means adding your Buttons and Items to the ListView and create a custom OnClickListener and Adapter to hold you Model. This Is the way I have used and I would do it again this way.
I your Adapter, you will need to Override:
getViewTypeCount - number of types of different row-layouts.
getItemViewType the type of the row.
getView returning the view for a position, here you need to inflate the layout and set the data.
This is a related question how to create a ListView with different types of rows.
I am loading some newsitems from a webservice I want to add these to a HorizontalScrollView.
On iOS I would achieve by looping my news items and then add text labels as subviews to a ScrollView. I'am trying to do something similar in android but I can't seem to get it to work properly. No matter what I do, the items are listed below each other.
Heres my code to add the views:
public void setupViews(ArrayList<News> news)
{
HorizontalScrollView scrollView = (HorizontalScrollView) getView().findViewById(R.id.horizontalScrollView);
LinearLayout layout = (LinearLayout) getView().findViewById(R.id.linearLayout);
for(int i = 0; i < news.size(); i ++)
{
News newsItem = news.get(i);
TextView head = new TextView(this.getActivity());
head.setText(newsItem.getHead());
head.setId(100+i);
layout.addView(head);
}
}
The XML looks like this:
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="150dp"
android:id="#+id/horizontalScrollView" android:layout_gravity="center"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="#+id/linearLayout">
</LinearLayout>
</HorizontalScrollView>
It might be worth noting that I am doing this inside an fragment..
you can only add a single child layout to a ScrollView
in your case :
add a horizontal LinearLayout (set orientation as horizontal via adding this to your LinearLayout android:orientation="horizontal")
add stuff inside the horizontal LinearLayout
and things will fall right into place, horizontally :-)
Is this possible?
I would display an activity that shows a welcome page, and that welcome page doesn't have any Views where I can attach an onClickListener.
EDIT: ok, the reason for this welcome kind of welcome page, is that this application is used to take something like a survey... after a customer is done with the survey, the app returns to this welcome page so another person can take the survey again.
Yes, if the original layout is somehow not appropriate, use a FrameLayout at the top level of your layout to achieve this. FrameLayout allows stackable views/layouts, so you can have your existing view as the bottom layer, and then a transparent view on top that listens for the touch event:
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- Put your complete original layout/view here -->
<View
android:id="#+id/view_to_listen_for_touch"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
try like this,
welcome screen xml layout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</RelativeLayout>
add this in your activity,
private RelativeLayout mainLayout;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_screen);
mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
mainLayout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// here you can write code to proceed next step.
}
});
}
I think you are using an XML layout for this page. And using at least one ViewGroup (e.g Linear Layout/Relative Layout etc). Put an id to this ViewGroup element and In the Activity initialize this ViewGroup element using find view by id. Now set the click listener to the ViewGroup element