Multi row view with uneven columns, data from adapter - android

I'm trying to create a view that would take data from an adapter and distribute it next to each other in rows. The view should rely on its width to decide when to put elements in next row. Please have a look on the ilustration, of what I'm trying to achieve.
http://i43.tinypic.com/2w327bq.png
I've found some great code here: Android - multi-line linear layout It generates linear layouts dynamically (puts horizontal layouts inside of an vertical layout). However, I would like to keep all this data in a single view and set an adapter on it. I would be grateful for any suggestions on how to achieve this.
Code snippet from quoted thread:
/**
* Copyright 2011 Sherif
* Updated by Karim Varela to handle LinearLayouts with other views on either side.
* #param linearLayout
* #param views : The views to wrap within LinearLayout
* #param context
* #param extraView : An extra view that may be to the right or left of your LinearLayout.
* #author Karim Varela
**/
private void populateViews(LinearLayout linearLayout, View[] views, Context context, View extraView)
{
extraView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// kv : May need to replace 'getSherlockActivity()' with 'this' or 'getActivity()'
Display display = getSherlockActivity().getWindowManager().getDefaultDisplay();
linearLayout.removeAllViews();
int maxWidth = display.getWidth() - extraView.getMeasuredWidth() - 20;
linearLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params;
LinearLayout newLL = new LinearLayout(context);
newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
newLL.setGravity(Gravity.LEFT);
newLL.setOrientation(LinearLayout.HORIZONTAL);
int widthSoFar = 0;
for (int i = 0; i < views.length; i++)
{
LinearLayout LL = new LinearLayout(context);
LL.setOrientation(LinearLayout.HORIZONTAL);
LL.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
LL.setLayoutParams(new ListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
views[i].measure(0, 0);
params = new LinearLayout.LayoutParams(views[i].getMeasuredWidth(), LayoutParams.WRAP_CONTENT);
params.setMargins(5, 0, 5, 0);
LL.addView(views[i], params);
LL.measure(0, 0);
widthSoFar += views[i].getMeasuredWidth();
if (widthSoFar >= maxWidth)
{
linearLayout.addView(newLL);
newLL = new LinearLayout(context);
newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
newLL.setOrientation(LinearLayout.HORIZONTAL);
newLL.setGravity(Gravity.LEFT);
params = new LinearLayout.LayoutParams(LL.getMeasuredWidth(), LL.getMeasuredHeight());
newLL.addView(LL, params);
widthSoFar = LL.getMeasuredWidth();
}
else
{
newLL.addView(LL);
}
}
linearLayout.addView(newLL);
}

Related

move button to the next line when there is no

I need to implement menu that can't be GridView or ListView. Items are next to each other and if there is no place, items should be display in next line as is visible on picture
I started implementation that is based on SpannableString and ReplacementSpan, but it supports only basic styling and I have problem with selected state.
What's the best way to implement such menu?
Maybe this will help you
/**
* Copyright 2011 Sherif
* Updated by Karim Varela to handle LinearLayouts with other views on either side.
* #param linearLayout
* #param views : The views to wrap within LinearLayout
* #param context
* #param extraView : An extra view that may be to the right or left of your LinearLayout.
* #author Karim Varela
**/
private void populateViews(LinearLayout linearLayout, View[] views, Context context, View extraView)
{
extraView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// kv : May need to replace 'getSherlockActivity()' with 'this' or 'getActivity()'
Display display = getActivity().getWindowManager().getDefaultDisplay();
linearLayout.removeAllViews();
int maxWidth = display.getWidth() - extraView.getMeasuredWidth() - 20;
linearLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params;
LinearLayout newLL = new LinearLayout(context);
newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
newLL.setGravity(Gravity.LEFT);
newLL.setOrientation(LinearLayout.HORIZONTAL);
int widthSoFar = 0;
for (int i = 0; i < views.length; i++)
{
LinearLayout LL = new LinearLayout(context);
LL.setOrientation(LinearLayout.HORIZONTAL);
LL.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
LL.setLayoutParams(new ListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
views[i].measure(0, 0);
params = new LinearLayout.LayoutParams(views[i].getMeasuredWidth(), LayoutParams.WRAP_CONTENT);
params.setMargins(5, 0, 5, 0);
LL.addView(views[i], params);
LL.measure(0, 0);
widthSoFar += views[i].getMeasuredWidth();
if (widthSoFar >= maxWidth)
{
linearLayout.addView(newLL);
newLL = new LinearLayout(context);
newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
newLL.setOrientation(LinearLayout.HORIZONTAL);
newLL.setGravity(Gravity.LEFT);
params = new LinearLayout.LayoutParams(LL.getMeasuredWidth(), LL.getMeasuredHeight());
newLL.addView(LL, params);
widthSoFar = LL.getMeasuredWidth();
}
else
{
newLL.addView(LL);
}
}
linearLayout.addView(newLL);
}
I finally discovered library called Android flow layout that works well https://github.com/ApmeM/android-flowlayout

Arrange RelativeLayout below another dynamically

I'm trying to dynamically build relative layouts consisting of an image and a textview at the moment. I have tried building a loop to place the next relative layout below the former one, but I can't really make it work. The end result should be something like this, but I guess that if i figure out how to align below the former one, I can also figure out how to place it right_of the former relative layout.
Any suggestions? This is my code so far:
RelativeLayout container1 = (RelativeLayout) rootView
.findViewById(R.id.main_layout);
for (int i = 0; i < pictures.size(); i++) {
RelativeLayout tile = new RelativeLayout(getActivity());
tile.setId(i);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.height = height / 3;
params.width = width / 2;
tile.setLayoutParams(params);
ImageButton ibGood = new ImageButton(getActivity());
ibGood.setId(1);
ibGood.setImageResource(pictures.get(0));
ibGood.setAdjustViewBounds(true);
ibGood.setMaxHeight(height / 3 / 5 * 4);
ibGood.setMaxWidth(width);
ibGood.setScaleType(ScaleType.CENTER_CROP);
ibGood.setPadding(5, 5, 5, 5);
tile.addView(ibGood);
RelativeLayout.LayoutParams tvPriceParam = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
tvPriceParam.addRule(RelativeLayout.BELOW, ibGood.getId());
tvPriceParam.addRule(RelativeLayout.ALIGN_LEFT, ibGood.getId());
TextView tvPrice = new TextView(getActivity());
tvPrice.setId(2);
tvPrice.setHeight(tile.getHeight() / 5);
tvPrice.setWidth(tile.getWidth() / 5 * 2);
tvPrice.setPadding(5, 0, 0, 5);
tvPrice.setText(Integer.toString(price.get(0)));
tile.addView(tvPrice, tvPriceParam);
if (counter == 0) {
container1.addView(tile);
} else if (counter % 2 == 0) {
RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lay.addRule(RelativeLayout.BELOW, -1);
tile.setLayoutParams(lay);
container1.addView(tile);
}
counter += 1;
}
you can make it with the custom gridview !! why you are doing this with the relative layout ?
here is the link which you can use to achieve what do you want..
http://www.learn-android-easily.com/2013/09/android-custom-gridview-example.html
http://www.caveofprogramming.com/uncategorized/custom-gridview-with-imageview-and-textview-in-android/
please visit 3 links are there you will get that you want .. with relative layout ..
Thanks,
Madhav

Android: Dynamically add views to ScrollView

I have a ScrollView and I want to insert a user specified number of HorizontalScrollViews. So what user says he wants to have a matrix of 5x5 elements, I want to insert 5 HorizontalScrollViews with 5 EditText objects each. My program adds the first line just as it's supposed to, but the rest not.
for (int i = 0; i < number; i++) {
LinearLayout ll = new LinearLayout(this);
ll.setLayoutParams(par2);
HorizontalScrollView row = new HorizontalScrollView(this);
row.setLayoutParams(par1);
row.addView(ll);
for (int j = 0; j < number; j++) {
EditText txt = new EditText(this);
txt.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
txt.setHint(i+","+j);
ll.addView(txt);
}
latout_in_scrollview.addView(row);
}
Any ideas why? Thanks!
EDIT:
The 1:1 code im using
LinearLayout dijkstra_rows;
FrameLayout.LayoutParams par1 = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams par2 = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_dijkstra);
dijkstra_rows = (LinearLayout) findViewById(R.id.dijkstra_rows);
Bundle extras = getIntent().getExtras();
number = extras.getInt("vertexes");
for (int i = 0; i < number; i++) {
LinearLayout ll = new LinearLayout(this);
ll.setLayoutParams(par2);
HorizontalScrollView row = new HorizontalScrollView(this);
row.setLayoutParams(par1);
row.addView(ll);
for (int j = 0; j < number; j++) {
EditText txt = new EditText(this);
txt.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
txt.setHint(i+","+j);
ll.addView(txt);
}
dijkstra_rows.addView(row);
}
}
ScrollView can contain only one childView. You can put any layout as per your requirement. I generally use Relative Layout...
Then add views dynamically to relative layout
viewLayout = (ViewGroup) mView.findViewById(R.id.YOUR_RELATIVE_LAYOUT_ID);
View lastCard = viewLayout.getChildAt(viewLayout.getChildCount() - 1);
// INFLATE YOUR NEW VIEW YOU WANT TO ADD
CardView cardView = (CardView)
LayoutInflater.from(getContext()).inflate(R.layout.card_nearest_stop, null);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//Set id to view
int id = 125;
if (lastCard != null) {
params.addRule(RelativeLayout.BELOW, lastCard.getId());
id = lastCard.getId() + 125;
}
cardView.setLayoutParams(params);
cardView.setId(id);
viewLayout.addView(cardView);
ScrollView is a single element container.
A ScrollView is a FrameLayout, meaning you should place one child in
it containing the entire contents to scroll; this child may itself be
a layout manager with a complex hierarchy of objects. A child that is
often used is a LinearLayout in a vertical orientation, presenting a
vertical array of top-level items that the user can scroll through.
You are adding multiple LinearLayouts here
for (int i = 0; i < number; i++) {
LinearLayout ll = new LinearLayout(this);
.
.
}
You should have only one out of this loop. Then add this one to your scrollView, in Loop you can add muliple HorizontolScrollViews to this LinearLayout

May I reuse LayoutPrams with ViewGroup.addView?

Does ViewGroup.addView clones LayoutParams data into inside or links to it? May I reuse the same instance of LayoutParams with multiple calls to addView() with different views?
There is nothing about it in apidoc.
WOW
The answer is NO (checked experimentally):
public class SymbolPadActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RelativeLayout.LayoutParams labelParams;
/*
* This block to reuse is not working
labelParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
labelParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
labelParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
*/
RelativeLayout mover = new RelativeLayout(this);
TextView textView;
for(int leftMargin = 0; leftMargin<3000; leftMargin += 100) {
for(int topMargin=0; topMargin<800; topMargin += 40) {
// I can't omit these 3 lines
labelParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
labelParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
labelParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
labelParams.leftMargin = leftMargin;
labelParams.topMargin = topMargin;
textView = new TextView(this);
textView.setText("(" + leftMargin + "," + topMargin + ")");
mover.addView(textView, labelParams);
}
}
RelativeLayout.LayoutParams moverParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
moverParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
moverParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
moverParams.leftMargin = 0;
moverParams.topMargin = 0;
RelativeLayout stator = new RelativeLayout(this);
stator.addView(mover, 0, moverParams);
setContentView(stator);
}
}
There is nothing about it in apidoc.
This means you need to make the more conservative choice, no matter what the current implementation is, as the implementation could change.
Hence, you need to assume that it is not safe to reuse an instance of LayoutParams with different Views.
For what it's worth, as far as I can tell, that is true anyway - ViewGroup doesn't make a copy.
This is an old question, but there seems to be an updated answer:
The LayoutParams has a constructor for copying another
Source: http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html
ViewGroup.LayoutParams(ViewGroup.LayoutParams source)
This would suggest not to re-use it, but perhaps to create 1 layout params object with everything you need, then just call
new LayoutParams(someLayoutParamsToReUse)
In my case, I wanted to set the layout params of a button to be the same as another button. I initially tried:
button.setLayoutParams(button2.getLayoutParams());
This will not work, however this should:
button.setLayoutParams(new LayoutParms(button2.getLayoutParams))'

Android: programmatically creating two columns in a table

showtimeTable = new TableLayout(this);
showtimeTable.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
for(int i=0;i<object.dateList.size();i++){
/* Create a new row to be added. */
TableRow tr = new TableRow(this);
tr.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
/* Create testview to be the row-content. */
mytext = new TextView(this);
mytext.setText(object.dateList.get(i).getTextDate());
mytext.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
mytext.setTextAppearance(this, R.style.detaileventDate);
tr.addView(mytext);
time = new TextView(this);
time.setText(object.dateList.get(i).getTime());
time.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
time.setTextAppearance(this, R.style.detaileventTime);
tr.addView(time);
/* Add row to TableLayout. */
showtimeTable.addView(tr,new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
}
layout.addView(showtimeTable);
I have this table all setup, but the two textfields are hugging each other. What I want to achieve is the appearance of two columns and have the time textfield on the right side.
I tried changing the margins in their respective Styles but that doesnt affect it.
I think you should use padding here. It will make padding of the Text view inside the table row. I have tried to do it with your code and just added some test lines:
mytext.setPadding(20, 3, 20, 3);
time.setPadding(20, 3, 20, 3);
It worked fine. Moreover, you can use "Gravity" for your purposes. See and example here: http://developer.android.com/resources/tutorials/views/hello-tablelayout.html
Table layout does not have concept of columns but you can add multiple views in table row by defining different width of those views.
Following code will specify size of column depending on specified colSpan value.
int COL_COUNT=2;
int mScreenWidthInDp = getScreenWidthInDip(activityContext);
private View getColumnItem(String colText, int colSpan) {
View view = mActivity.getLayoutInflater().inflate(R.layout.table_column_view, null);
TextView textView = (TextView) view.findViewById(R.id.tablet_title);
textView.setText(colText);
int columnWidth = (mScreenWidthInDp / COL_COUNT) * span;
TableRow.LayoutParams params = new TableRow.LayoutParams(columnWidth, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
params.span = colSpan;
view.setLayoutParams(params);
return view;
}
public static int getScreenWidthInDip(Activity context) {
if (mScreenWidthInDp == 0) {
WindowManager wm = context.getWindowManager();
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int screenWidth_in_pixel = dm.widthPixels;
float screenWidth_in_dip = screenWidth_in_pixel / dm.density;
mScreenWidthInDp = (int) screenWidth_in_dip;
}
return mScreenWidthInDp;
}
you can set layout weight parameter for the table row. This will arrange the childrens accordingly.
mytext.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT, TableRow.LayoutParams.WRAP_CONTENT,1f));
The final parameter is the layout weight

Categories

Resources