I've been trying to create a custom view that is to be used to indicate the battery level of a proprietary device.
So when the battery level of the device is read the method setPercentage(int batteryLevel) is called on the custom view :
The problem is that regardless of what value I set nothing seems to change in the custom view.
Here is the class :
public class RectangleView extends LinearLayout {
private ArrayList<ImageView> views = new ArrayList<ImageView>();
public RectangleView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
init(context);
}
public RectangleView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
this.setOrientation(LinearLayout.HORIZONTAL);
for (int i = 0; i < 10; i++) {
ImageView loadingPiece = new ImageView(context);
loadingPiece.setBackgroundColor(Color.BLACK);
this.addView(loadingPiece);
LayoutParams layoutParams = (LayoutParams)loadingPiece.getLayoutParams();
layoutParams.weight = 1.0f;
layoutParams.height = this.getHeight();
layoutParams.width = 0;
loadingPiece.setLayoutParams(layoutParams);
views.add(loadingPiece);
}
}
public void setPercentage(int amountToShow) {
for (int i = 0; i < views.size(); i++)
if (i < amountToShow)
views.get(i).setVisibility(View.VISIBLE);
else
views.get(i).setVisibility(View.INVISIBLE);
}
}
Caling setPersentage(5) should show 5 imageviews - However nothing is changed and the view itself seems empty.
I think that happens because of the LayoutParams you used(getHeight() returning 0 at that moment). See if this makes a difference:
this.setOrientation(LinearLayout.HORIZONTAL);
for (int i = 0; i < 10; i++) {
ImageView loadingPiece = new ImageView(context);
loadingPiece.setBackgroundColor(Color.BLACK);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.FILL_PARENT, 1.0f);
this.addView(loadingPiece, lp);
views.add(loadingPiece);
}
I think it would be easier to use a simple view with a custom drawable for background and render that background differently depending on the percentage. Or why not use a ProgressBar?
Related
I have a constraintLayout that contains multiple nodeView's. A nodeView is a ImageView line attached to the left side of a ImageView circle
I now want to connect X amount of nodes together. To programmatically set constraints, you use the R.id, but since I'm connecting multiple same nodes together, and they all share the same R.id, this isn't working. Is there any way to reference a specific view's ImageView as a reference for setting a constraint for another ImageView? I'm starting to think I'm approaching this the wrong way entirely. Thanks.
EDIT: Here is the rest of the code.
node code
private void init(Context context, AttributeSet attrs, String description, boolean active, boolean base) {
View inflatedView = inflate(context, R.layout.tracking_node, this);
nodeLine = inflatedView.findViewById(R.id.imageNodeLine);
nodeImage = inflatedView.findViewById(R.id.imageNode);
nodeText = inflatedView.findViewById(R.id.textNode);
nodeLine.setId(View.generateViewId());
nodeImage.setId(View.generateViewId());
nodeText.setText(description);
if (active){
nodeImage.setImageResource(R.drawable.circle_green);
nodeLine.setImageResource(R.color.support_success);
}else{
nodeImage.setImageResource(R.drawable.circle_grey);
nodeImage.setImageResource(R.color.grey);
}
//Remove left-side connecting line if base node
if (base){
nodeLine.getLayoutParams().width = 20;
nodeLine.setImageResource(R.color.transparent);
}
}
public int getNodeImageId(){
return nodeImage.getId();
}
public int getNodeLineId(){
return nodeLine.getId();
}
constraintLayout code
private void init(Context context, AttributeSet attrs) {
View inflatedView = inflate(context, R.layout.delivery_status_view, this);
deliveryTrackerView = inflatedView.findViewById(R.id.linearLayoutDeliveryTracking);
shippingDetailsButton = inflatedView.findViewById(R.id.btnShippingDetails);
//steps[] is a string array that contains the content of each node
DeliveryNodeView node = new DeliveryNodeView(context, attrs, steps[0], true, true);
//Saves resource ID of last node image
int pastNodeID = node.getNodeImageId();
//Generates nodes
for (int i = 1; i < steps.length; i++){
boolean active = ((i + 1) / currentStep) <= 1;
node = new DeliveryNodeView(context, attrs, steps[i], active, false);
int nodeLineID = node.getNodeLineId();
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(deliveryTrackerView);
deliveryTrackerView.addView(node);
constraintSet.connect(nodeLineID, ConstraintSet.START, pastNodeID, ConstraintSet.END);
pastNodeID = node.getNodeImageId();
}
}
There are a few problems with your code. Here is some sample code that builds a 5x5 colored box array that looks like this:
The comments in the code outline the key steps. activity_main.xml is just an empty ConstraintLayout.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConstraintLayout layout = findViewById(R.id.layout);
int colorCounter = 0;
int idToTop = ConstraintSet.PARENT_ID;
int idToTopSide = ConstraintSet.TOP;
for (int i = 0; i < 5; i++) {
int idToLeft = ConstraintSet.PARENT_ID;
int idToLeftSide = ConstraintSet.START;
for (int j = 0; j < 5; j++) {
View box = getBox(colorCounter++ % 2 == 0);
// Add the view before getting the ConstraintSet.
layout.addView(box);
ConstraintSet cs = new ConstraintSet();
cs.clone(layout);
// Must constrain the view horizontally...
cs.connect(box.getId(), ConstraintSet.START, idToLeft, idToLeftSide);
//... and vertically.
cs.connect(box.getId(), ConstraintSet.TOP, idToTop, idToTopSide);
idToLeft = box.getId();
idToLeftSide = ConstraintSet.END;
// Apply the ConstraintSet to the layout.
cs.applyTo(layout);
}
idToTop = idToLeft;
idToTopSide = ConstraintSet.BOTTOM;
}
}
private View getBox(boolean isRed) {
View view = new View(this);
view.setId(View.generateViewId());
view.setBackgroundColor((isRed) ? Color.RED : Color.BLUE);
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(200, 200);
view.setLayoutParams(lp);
return view;
}
}
Alternate code with the same result that separates out the view creation from making of the ConstraintSet connections. This may be a little more efficient.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConstraintLayout layout = findViewById(R.id.layout);
int colorCounter = 0;
int[][] connections = new int[5][5];
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
View box = getBox(colorCounter++ % 2 == 0);
// Add the view before getting the ConstraintSet.
layout.addView(box);
connections[row][col] = box.getId();
}
}
int idToTop = ConstraintSet.PARENT_ID;
int idToTopSide = ConstraintSet.TOP;
ConstraintSet cs = new ConstraintSet();
cs.clone(layout);
for (int i = 0; i < 5; i++) {
cs.connect(connections[i][0], ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
cs.connect(connections[i][0], ConstraintSet.TOP, idToTop, idToTopSide);
for (int j = 1; j < 5; j++) {
// Must constrain the view horizontally...
cs.connect(connections[i][j], ConstraintSet.START, connections[i][j - 1], ConstraintSet.END);
//... and vertically.
cs.connect(connections[i][j], ConstraintSet.TOP, idToTop, idToTopSide);
// Apply the ConstraintSet to the layout.
}
idToTop = connections[i][0];
idToTopSide = ConstraintSet.BOTTOM;
}
cs.applyTo(layout);
}
private View getBox(boolean isRed) {
View view = new View(this);
view.setId(View.generateViewId());
view.setBackgroundColor((isRed) ? Color.RED : Color.BLUE);
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(200, 200);
view.setLayoutParams(lp);
return view;
}
}
I need to make a 2048 game in Android.
For the Board we need use a GridLayout and set it up programatically.
It will be a 4x4 grid just like the original game.
For the card we have to use a FrameLayout with a TextView and center it.
Original game screenshot
My result screenshot
This is what I already have:
public class Board extends GridLayout {
private final int BOARD_WIDTH = 4;
private final int BOARD_HEIGHT = 4;
private Card[][] cards;
public Board(Context context) {
super(context);
initBoard();
}
public Board(Context context, AttributeSet attrs) {
super(context, attrs);
initBoard();
}
public Board(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initBoard();
}
public void initBoard() {
this.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.colorBoard));
this.setRowCount(BOARD_HEIGHT);
this.setColumnCount(BOARD_WIDTH);
Random random = new Random();
cards = new Card[BOARD_WIDTH][BOARD_HEIGHT];
for (int x = 0; x < BOARD_WIDTH; x++) {
for (int y = 0; y < BOARD_HEIGHT; y++) {
int n = random.nextInt(2);
cards[x][y] = new Card(this.getContext(), (n * 2));
}
}
}
public void addCardsToBoard() {
for (int x = 0; x < BOARD_WIDTH; x++) {
for (int y = 0; y < BOARD_HEIGHT; y++) {
GridLayout.LayoutParams param = new LayoutParams();
param.height = LayoutParams.WRAP_CONTENT;
param.width = LayoutParams.WRAP_CONTENT;
param.setGravity(Gravity.CENTER);
param.columnSpec = GridLayout.spec(x);
param.rowSpec = GridLayout.spec(y);
param.topMargin = 50;
Card c = cards[x][y];
c.setLayoutParams(param);
this.addView(cards[x][y], 230, 230);
}
}
}
}
-
public class Card extends FrameLayout {
private int number = 0;
private TextView txtNumber;
public Card(Context context, int n) {
super(context);
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
txtNumber = new TextView(context);
txtNumber.setTextSize(30);
txtNumber.setLayoutParams(params);
this.addView(txtNumber);
setNumber(n);
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
this.setBackgroundColor(ContextCompat.getColor(getContext(), number == 0 ? R.color.colorCard : R.color.colorCardActive));
txtNumber.setText(number == 0 ? "" : "" + number);
}
}
Anything I can do to make it look better (more like the original game).
Any tips/advice is appreciated.
Add horizontal and vertical spacing to GridLayout, that is applicable to it's column and row.
view.setHorizontalSpacing(10);
view.setVerticalSpacing(10);
I am new to Android Development. I have been working with using a GridLayout to display Dynamically inserted ImageViews.
My issue is located in "onFocusWindowChanged" but I pasted my onCreate where I do my assignments of the images.
private List<Behavior> behaviors = null;
private static int NUM_OF_COLUMNS = 2;
private List<ImageView> images;
private GridLayout grid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_behaviors);
XMLPullParserHandler parser = new XMLPullParserHandler();
try {
behaviors = parser.parse(getAssets().open("catagories.xml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
grid = (GridLayout) findViewById(R.id.behaviorGrid);
images = new ArrayList<ImageView>();
grid.setColumnCount(NUM_OF_COLUMNS);
grid.setRowCount(behaviors.size() / NUM_OF_COLUMNS);
for (Behavior behavior : behaviors)
images.add(this.getImageViewFromName(behavior.getName()));
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
View view = (View) findViewById(R.id.scrollView);
int width = (int) (view.getWidth() * .45);
Log.i("ViewWidth", Integer.toString(width));
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
int childCount = images.size();
ImageView image;
for (int i = 0; i < childCount-1; i++) {
image = images.get(i);
image.setLayoutParams(lp);
grid.addView(image);
}
}
In my (short) previous experience, using
grid.add(View);
worked fine, but now I am only seeing the last child display only. Looking through the debugger I can see that the gridview is being populated with more than just the last element, as well as the last imageview.
Thank you for your help
you should create a GridLayout.LayoutParams for each ImageView:
for (int i = 0; i < childCount-1; i++) {
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
......
}
GridLayout.LayoutParams contains location information, e.g [column:2, row:3]. In your code, all ImageViews are set the same GridLayout.LayoutParams, so they are located in the same cell(overlapping each other).
When use LinearLayout.LayoutParams instead, there is no location information in it. GridLayout will create a new GridLayout.LayoutParams for each child view, so all ImageViews use their own different GridLayout.LayoutParams and location.
Wish this help. You can read the GridLayout.java and ViewGroup.java for more details.
So I solved my issue, although I'm not sure how-
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
changed to...
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(x,y);
made it work just as I wanted it. But I'm not sure why- If anyone could explain, please do :)
I'm creating dinamically a LinearLayout (a custom Class that extends LinearLayout) with a RadioGroup inside it. I'm adding RadioButtons dinamically also. This LinearLayout class is used in several Activities and Fragments.
The strange behaviour is that the second time I add LinearLayout, when OnCheckedChanged is called, a get an index that doesn't exists in my current RadioGroup. I't seems that every time I create a new Instance of my LinearLayout, RadioGroup thinks that RadioButtons added previously are still there.
For example, if I create a custom LinearLayout and I add four items and after that I create another LinearLayout (in other Activity) with other 4 items, when I click in the first item (on the second Activity), I get a 5 as clicked item position.
This is my custom LinearLayout class:
public class AgrupacionConmutadorLayout extends LinearLayout{
private static final String TAG = "AgrupacionConmutadorLayout";
private int[] mColorFromLevel = {R.color.inspeccion_aparato_agrupacion_color_level_1, R.color.inspeccion_aparato_agrupacion_color_level_2,
R.color.inspeccion_aparato_agrupacion_color_level_3, R.color.inspeccion_aparato_agrupacion_color_level_4, R.color.inspeccion_aparato_agrupacion_color_level_5};
private Context mContext;
private LinearLayout dataContainer;
private TextView mTitle;
private RelativeLayout mSubAgrupacionesContainer;
private LinearLayout mDataAndSubAgrupacionesContainer;
private RadioGroup mConmutadorContainer;
private ArrayList<View> mLayoutsDataContained = new ArrayList<View>();
private int mLevel;
private LinearLayout mTitleContainer;
private InspeccionesFormWidgetReceiver mModificationReceiver;
private boolean isEdicion;
public AgrupacionConmutadorLayout(Context context) {
super(context);
this.mContext = context;
init(null, 0);
}
public AgrupacionConmutadorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init(attrs, 0);
}
public AgrupacionConmutadorLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
dataContainer = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.ins_agrupacion_conmutador_container, this);
mTitle = (TextView) dataContainer.findViewById(R.id.ins_agrupacion_container_title);
mSubAgrupacionesContainer = (RelativeLayout) findViewById(R.id.rl_ins_subagrupacion_container);
mConmutadorContainer = (RadioGroup) findViewById(R.id.ins_agrupacion_conmutador_radio_group);
mDataAndSubAgrupacionesContainer = (LinearLayout) findViewById(R.id.ll_ins_data_and_subagrupacion_container);
mTitleContainer = (LinearLayout) findViewById(R.id.ll_ins_agrupacion_container_title);
mConmutadorContainer.removeAllViews();
mConmutadorContainer.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int pos) {
Log.d(TAG, "onCheckedChanged Clicked pos: " + pos);
Log.d(TAG, "onCheckedChanged RadioGroup size: " + radioGroup.getChildCount());
Log.d(TAG, "onCheckedChanged " + mLayoutsDataContained.size());
//OnCheckedChanged comienza a devolver en 1, al ArrayList en 0
for (int i = 1; i < mLayoutsDataContained.size() + 1; i++) {
if (i == pos) {
mLayoutsDataContained.get(i - 1).setVisibility(View.VISIBLE);
} else {
mLayoutsDataContained.get(i - 1).setVisibility(View.GONE);
}
}
}
});
}
public void initialice(AgrupacionSios agrupacionSios, InspeccionesFormWidgetReceiver modificationReceiver, boolean isEdicion) {
this.mModificationReceiver = modificationReceiver;
this.isEdicion = isEdicion;
mTitle.setText(agrupacionSios.getTitle());
mTitle.setTextColor(mContext.getResources().getColor(mColorFromLevel[agrupacionSios.getLevel()]));
if (agrupacionSios.isOcultarContenedor()) mTitleContainer.setVisibility(View.GONE);
if (agrupacionSios.getNumOfSons() > 0) {
drawSubAgrupaciones(agrupacionSios);
}
this.refreshDrawableState();
}
private void drawSubAgrupaciones(AgrupacionSios agrupacionSios) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
ArrayList<AgrupacionSios> agrupaciones = agrupacionSios.getAgrupacionesHijos();
Iterator itAgr = agrupaciones.iterator();
while (itAgr.hasNext()) {
AgrupacionSios agrupacionHija = (AgrupacionSios) itAgr.next();
if (agrupacionHija.getNumOfLevels() > 0 || agrupacionHija.getNumOfSons() > 0) {
switch (agrupacionHija.getTipoSubAgrupaciones()) {
case CONMUTADOR:
AgrupacionConmutadorLayout v = new AgrupacionConmutadorLayout(mContext);
v.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(v, layoutParams);
mLayoutsDataContained.add(v);
break;
case COLUMNAS:
AgrupacionColumnasLayout vCol = new AgrupacionColumnasLayout(mContext);
vCol.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(vCol, layoutParams);
mLayoutsDataContained.add(vCol);
break;
default:
AgrupacionGenericaLayout vGen = new AgrupacionGenericaLayout(mContext);
vGen.isSonOfConmutador(true);
vGen.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(vGen, layoutParams);
mLayoutsDataContained.add(vGen);
break;
}
}
//Añadimos el botón de conmutación correspondiente a la subagrupación.
addAgrupacionToConmutadorContainer(agrupacionHija);
}
mConmutadorContainer.check(1);
}
public void setBackgroundColor(int color) {
setBackgroundResource(color);
}
private void addAgrupacionToConmutadorContainer(AgrupacionSios mAgrupacion) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
RadioButton b = new RadioButton(mContext);
b.setLayoutParams(layoutParams);
b.setText(mAgrupacion.getTitle());
b.setButtonDrawable(android.R.color.transparent);
b.setBackground(mContext.getResources().getDrawable(R.drawable.ins_conmutador_radio_background));
b.setPadding(20,5,20,5);
RadioGroup.LayoutParams params
= new RadioGroup.LayoutParams(mContext, null);
params.setMargins(10, 0, 10, 0);
b.setLayoutParams(params);
mConmutadorContainer.addView(b);
}
}
And this is the way I create AgrupacionConmutadorLayout on Activities & Fragments:
AgrupacionConmutadorLayout vConm = new AgrupacionConmutadorLayout(this);
vConm.initialice(agrupacion, this, isEdicion);
vConm.setVisibility(View.VISIBLE);
mAgrupacionesContainer.addView(vConm, layoutParams);
-----------------SOLUTION---------------------------
Marius answer was the key, I was getting clicked RadioButton id, not his position inside RadioGroup.
Finally I have done it by using tags. I set its order to every RadioButton as a tag:
private void addAgrupacionToConmutadorContainer(AgrupacionSios mAgrupacion) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
RadioButton b = new RadioButton(mContext);
b.setLayoutParams(layoutParams);
b.setText(mAgrupacion.getTitle());
b.setButtonDrawable(android.R.color.transparent);
b.setBackground(mContext.getResources().getDrawable(R.drawable.ins_conmutador_radio_background));
b.setPadding(20, 5, 20, 5);
RadioGroup.LayoutParams params
= new RadioGroup.LayoutParams(mContext, null);
params.setMargins(10, 0, 10, 0);
b.setLayoutParams(params);
b.setTag(mConmutadorContainer.getChildCount());
mConmutadorContainer.addView(b);
}
And I get that tag in OnCheckedChangeListener:
mConmutadorContainer.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int clickedId) {
View radioButtonClicked = radioGroup.findViewById(clickedId);
if (radioButtonClicked != null) {
Integer pos = (Integer) radioButtonClicked.getTag();
Log.d(TAG, "onCheckedChanged RadioGroup clicked position: " + pos);
for (int i = 0; i < mLayoutsDataContained.size(); i++) {
View view = mLayoutsDataContained.get(i);
if (pos.intValue() == i) {
view.setVisibility(View.VISIBLE);
} else view.setVisibility(View.GONE);
}
}
}
});
You must have misread the API. Second parameter is NOT position. It's the id, of the button. There are several solutions to your problem.
Adding id, based on position:
//not recommended way, as activity.findViewById uses this id, I GUESS something wrong may happen
private int currId;
...
b.setId(currId);
currId++;
container.addView(b);
Adding a tag:
//recommended
b.setTag(mAgrupacion);
container.addView(b);
//then...
AgrupacionSios tag = (AgrupacionSios) b.getTag();
//do action based on tag information
Use this.
for (int i = 0; i < mLayoutsDataContained.size(); i++) {
if (i == pos) {
mLayoutsDataContained.get(i - 1).setVisibility(View.VISIBLE);
} else {
mLayoutsDataContained.get(i - 1).setVisibility(View.GONE);
}
}
I would like to inflate a LinearLayout with multiple instances of another LinearLayout. How can I do that? My problem is that I seem to always use the same instance and hence add that instance over and over again.
In short: What I need is a way to add new instances of a LinearLayout child to another LinearLayout parent.
Here is what I have done so far:
private void setupContainers() {
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(MainActivity.LAYOUT_INFLATER_SERVICE);
LinearLayout parentContainer = (LinearLayout)this.findViewById(R.id.parent_container);
for (int i = 0; i < someNumber; i++) {
LinearLayout childContainer = (LinearLayout) layoutInflater.inflate(R.layout.child_container, null);
parentContainer.addView(childContainer);
}
}
Try this:
for (int i = 0; i < someNumber; i++) {
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); // or any other layout params that suit your needs
LinearLayout childContainer = new LinearLayout(this);
parentLayout.addView(childContainer, params)
}
EDIT
Considering you need to use the content from XML, you'll need to create a custom class that extends LinearLayout and initialize in there all its properties. Something like:
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyLinearLayout(Context context) {
super(context);
init(context);
}
private void init(Context context) {
inflate(context, R.id.R.layout.child_container, this);
// setup all your Views from here with calls to getViewById(...);
}
}
Also, since your custom LieanrLayout extends from LinearLayout you can optimize the xml by replacing the root <LinearLayout> element with <merge>. Here is a short documentation and an SO link. So the for loop becomes:
for (int i = 0; i < someNumber; i++) {
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); // or any other layout params that suit your needs
LinearLayout childContainer = new MyLinearLayout(this);
parentLayout.addView(childContainer, params); // feel free to add or not the LayoutParams object
}