Nested Views are not rendering - android

new to this site so sorry if this question is inappropriate, or in the wrong section.
Android:
I have written a custom button class which extends View and works just fine. Now I want to create a numeric keypad class which uses several of these custom buttons arranged in a particular way, which I can then use in a phone dialler app. I can build the keypad from within the app's main activity, and it seems ok, but I want to build this keypad inside its own class for easy re-use. When I move the code into its own class I get either errors or nothing drawn on screen. I think part of the problem is what class the child views are being added to.
Here's my code in the main activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(1);
LcarsButton numericPad[] = new LcarsButton[10]; //array of buttons
LinearLayout rows[] = new LinearLayout[3];
for(int i=0;i<=2;i++)
{
rows[i] = new LinearLayout(this);
for(int j=1;j<=3;j++)
{
int k = (i * 3) + j;
numericPad[k] = new LcarsButton(this);
numericPad[k].label = "" + k;
rows[i].addView(numericPad[k]);
}
layout.addView(rows[i]);
}
It loops through the array numericPad, assigning 3 buttons to each 'row', then 3 'row's to the 'layout'. This works fine.
Here's the code as seen in the class constructor:
public class LcarsNumPad extends LinearLayout {
public LcarsNumPad(Context context) {
super(context);
this.setOrientation(VERTICAL);
LinearLayout layout = new LinearLayout(context);
LcarsButton numericPad[] = new LcarsButton[10];
layout.setOrientation(1);
LinearLayout rows[] = new LinearLayout[3];
for(int i=0;i<=2;i++)
{
rows[i] = new LinearLayout(context);
for(int j=1;j<=3;j++)
{
int k = (i * 3) + j;
numericPad[k] = new LcarsButton(context);
numericPad[k].label = "" + k;
rows[i].addView(numericPad[k]);
}
layout.addView(rows[i]);
}
As you can see the only differences in the code are to accommodate the context of each particular piece of code. Can anyone tell me where I am going wrong?

I guess the reason of Error is you are using layout variable which is defined in onCreate(). You need to pass the rows array to the main activity and from there you can add it to the layout.

Related

Find child of a LinearLayout inside a LinearLayout

I have a LinearLayout ("ll") that is already created in xml and the app dynamically creates another LinearLayout inside of it and creates an EditText and a Button inside of that view. The button makes the whole LinearLayout destroy itself along with the EditText and Button inside it (the whole system is a player name entering activity). Anyway, I am trying to find a way to get the text from all of the EditTexts. I have tried using a for loop on "ll" and using ll.getChildAt() but I can't seem to use .getChildAt() on whatever ll.getChildAt() generates because getChildAt() generates a "View" not a "LinearLayout." I basically just need a way to search two children in, rather than just one. Also, if there is just a better way I should be doing this, let me know. I'm open to suggestions.
Here's my code if it will help:
NewGameCreate.java
public class NewGameCreate extends Activity {
int numOfPlayers = 0;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_game_create);
}
public void newPlayer(View view) {
numOfPlayers++;
final LinearLayout ll = findViewById(R.id.playerView);
final LinearLayout llNew = new LinearLayout(getApplicationContext());
llNew.setOrientation(LinearLayout.HORIZONTAL);
llNew.setId(numOfPlayers);
ll.addView(llNew);
EditText newName = new EditText(this);
newName.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
newName.setHint("Enter Player Name");
newName.setId(numOfPlayers);
newName.setWidth(0);
llNew.addView(newName);
final Button delete = new Button(this);
delete.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0));
delete.setText("Delete");
delete.setId(numOfPlayers);
delete.setWidth(0);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int id = delete.getId();
ll.removeViewInLayout(findViewById(id));
Drawable back = ll.getBackground();
ll.setBackgroundColor(00000000);
ll.setBackground(back);
ll.invalidate();
}
});
llNew.addView(delete);
}
public void startGame(View view){
LinearLayout ll = findViewById(R.id.playerView);
List text = new ArrayList();
for(int loop = 0; loop < ll.getChildCount(); loop++) {
//this is the code in question and where I want to get the text from
//all my EditTexts
LinearLayout inner = ll.getChildAt(loop);
}
}
}
I think I found the answer to it. You need to change a little bit of code in the startGame() method I m providing the code for startGame below.
public void startGame(View view) {
LinearLayout ll = findViewById(R.id.playerView);
List text = new ArrayList();
for (int loop = 0; loop < ll.getChildCount(); loop++) {
//this is the code in question and where I want to get the text from
//all my EditTexts
LinearLayout inner = (LinearLayout) ll.getChildAt(loop);
for (int j = 0; j < inner.getChildCount(); j++) {
if (inner.getChildAt(j) instanceof EditText) {
EditText textET = (EditText) inner.getChildAt(j);
Log.d("TAG",textET.getText().toString());
}
}
}
}
In the above code you were able to get the first child only but as you have added a linearLayout with orientation Horizontal in a parent LinearLayout with orientation Vertical, you have written code for the child of parent layout i.e playerView. I have modified the code to get the elements of the child Linear layout and Log prints all the text from the EditText.
Hope that helps!!

How I can save a linear layout and all its inner views and use it later android

I have one activity and inside it I have a Linear layout (lets name it the "main linear layout") and I am adding dynamically created view inside it (text views, linear layouts, edit texts, ...etc).
In the bottom of the screen there are two button (next and back).
If the user clicked on next button I should save the current "main linear layout " in a list for example and then I am generating a new views and I add it inside the "main linear layout" then .
And if the user clicked on back button I should restore the "main linear layout" and show all its views.
I don't know how I can do it.
I hope my description is clear :)
Take a look at onSaveInstance for preserving the view on the main screen when leaving to a different activity or screen orientation.
You can also try and use the buttons to hide the layouts using Visibility instead of trying to navigate through them.
This may help you. but concrete code need you write it yourself.
public class TestActivity extends Activity{
Stack<LinearLayout> layouts = new Stack<>();
FrameLayout container;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button btnPre = new Button(this);
Button btnNext = new Button(this);
btnPre.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
container.addView(layouts.pop());
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayout linearLayout = (LinearLayout) container.getChildAt(0);
layouts.push(linearLayout);
container.removeAllViews();
container.addView(createNextView());
}
});
}
private LinearLayout createNextView(){
LinearLayout linearLayout = new LinearLayout(this);
return linearLayout;
}
}
Thank you all for your comments.
I haven't test Cyrus answer. I will post my answer as well in case someone has the same problem in Xamarin.Android since I am using it.
I fixed it like this:
I added this in next button click event and previous button click event:
AddQuestionsLinearLayoutToPagesLinearLayoutsList();
And the AddQuestionsLinearLayoutToPagesLinearLayoutsList() body is, of course you can change it the way you want:
private void AddQuestionsLinearLayoutToPagesLinearLayoutsList()
{
//Create a new linear layout to add views into it and saved it in _mPagesLinearLayouts list at index _mPageIndex
LinearLayout savedLinearLayout = new LinearLayout(this);
//List of _mQuestionsLinearLayout views
List<View> views = new List<View>();
//Add all _mQuestionsLinearLayout to views list
for (int i = 0; i < _mQuestionsLinearLayout.ChildCount; i++)
{
views.Add(_mQuestionsLinearLayout.GetChildAt(i));
}
//Remove views from main questions linear layout
_mQuestionsLinearLayout.RemoveAllViews();
//Add all views from the views list to savedLinearLayout
for (int i = 0; i < views.Count; i++)
{
savedLinearLayout.AddView(views[i]);
}
//Add savedLinearLayout to _mPagesLinearLayouts list at index _mPageIndex
_mPagesLinearLayouts.Insert(_mPageIndex, savedLinearLayout);
}
In creating views method:
if(NeedToCreateViews())
{
//create views here and add it to _mQuestionsLinearLayout
}
//Get all saved views and add it to _mQuestionsLinearLayout
else
{
//List of _mPagesLinearLayouts[_mPageIndex] LinearLayout views
List<View> views = new List<View>();
//Add all _mPagesLinearLayouts[_mPageIndex] LinearLayout to views list
for (int i = 0; i < _mPagesLinearLayouts[_mPageIndex].ChildCount; i++)
{
views.Add(_mPagesLinearLayouts[_mPageIndex].GetChildAt(i));
}
//Remove all views from _mPagesLinearLayouts[_mPageIndex] linear layout
_mPagesLinearLayouts[_mPageIndex].RemoveAllViews();
//Remove the linear layout at index _mPageIndex
_mPagesLinearLayouts.RemoveAt(_mPageIndex);
//Add all views from views list to _mQuestionsLinearLayout
for (int i = 0; i < views.Count; i++)
{
_mQuestionsLinearLayout.AddView(views[i]);
}
}

Android: deleting programmatically added image buttons with ID's

hows it going? I'm creating a little training app for a project, its going fine except for a formatting problem im getting. So, ive a csv file with a name and age for a client. an array is created from this, then I've got a scroll View containing a grid layout and i create Image Buttons from the client array. that's all fine. ive got an add client button at the end of this, the button and its activity work fine, but when you come back to the main screen, the buttons are all screwed up (huge, misplaced etc). So i figured i would loop through and delete all the buttons and repopulate the main screen, except, since i programmatically created them, i cant figure out how to find them to delete them. i tried setting their id's to the index of the array, but then i get a null pointer error.
Function where the buttons are created:
public void fillActivity_main(){
if(listPopulated == false) { // check to see if its aready been created
populateClientList();//fill array with client objects
listPopulated = true;
}
//setup asset manager
AssetManager am = getApplicationContext().getAssets();
//Create the "GridLayout Image Board"
GridLayout buttonBoard = (GridLayout) findViewById(R.id.buttonboard);
int idealWidth = buttonBoard.getWidth(); //get width of the board
int idealHeight = buttonBoard.getHeight() / 2;//same
//create the Listeners, this is a place holder for now but will eventually use SetCurrentClient() (or maybe just switch to Start screen, with the current client?)
View.OnClickListener imageClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("CLICK AT: " + v.getId());
Client temp = clientList[v.getId()];
Intent i = new Intent(getApplicationContext(), DisplayClient.class);
System.out.println(temp.getName());
i.putExtra("name", temp.getName());
System.out.println(i.getStringExtra("name"));
i.putExtra("age", Integer.toString(temp.getAge()));
startActivity(i);
}
};
int j = 0; //used the keep track of the id's we set for the buttons
for (int i = 0; i < clientList.length; i++) {
if (clientList[i] != null) {
//creation and ID setting
ImageButton imgbutton = (ImageButton) new ImageButton(this);
imgbutton.setId(i);
//Layout shit
imgbutton.setImageResource(R.mipmap.ic_launcher);
imgbutton.setMinimumWidth(idealWidth);
imgbutton.setMinimumHeight(idealHeight);
imgbutton.setOnClickListener(imageClickListener);
//check and set image
if(clientList[i].getClientImage().equals(" ")) {
try{
imgbutton.set(am.openFd(clientList[i].getClientImage()));}
catch(Exception ex){
ex.toString();
}
Log.d("ClientImageCheck", "No picture found for " + clientList[i].getName());
}
buttonBoard.addView(imgbutton);
j++;
}
}
//create the new Client Button at the end of all the rest.
Button newClientButton = (Button) new Button(this);
newClientButton.setText("+"); // obvious
newClientButton.setLayoutParams(new LinearLayout.LayoutParams(GridLayout.LayoutParams.WRAP_CONTENT, GridLayout.LayoutParams.WRAP_CONTENT));
newClientButton.setWidth(idealWidth);
newClientButton.setHeight(idealHeight);
View.OnClickListener newClientListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), CreateClientForm.class);
startActivityForResult(i, 199);
//System.out.println("Doing good so far, leaving the createclient form bnut still in main");
}
}; // create listener
newClientButton.setOnClickListener(newClientListener); // assign listener
buttonBoard.addView(newClientButton); //add the button the buttonBoard, after all the clients have been added
}
Function where i do the deleting:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//Check which request we're responding to
if (requestCode == 199) {
// Make sure request was successful
if (resultCode == RESULT_OK) {
// The user made a name and crap.
Bundle extras = data.getExtras();
String name = extras.getString("name");
int age = extras.getInt("age");
Client temp = new Client(name, age);
addClientToArray(temp);
System.out.println(name + "attempted add to array");
}
for(int i = 0; i<clientList.length; i++ ){
View v = findViewById(i);
((ViewManager) v.getParent()).removeView(v);
}
fillActivityMain();
}
if i've got the logic right, the 'i' in the loop should be the appropriate id. Granted, the teach has kind of thrown us in the deep end for this project, never taken mobile apps or anything, so all this code is the result of me googling issues as i run into them. I've read the basics for Views, intents, etc, but there must be something i'm missing.
I've tried making the gridLayout that the buttons sit on a class variable so i could call it buttonBoard.removeView(i) or something.
ive also tried `
for(int i = 0; i<clientList.length; i++ ){
ImageButton btn = (ImageButton) findViewByid(i);
((ViewManager) v.getParent()).removeView(btn);
}
Can you add the replacement images at the same time that you delete the existing images? If so, try this:
for(int i = 0; i < buttonBoard.getChildCount(); i++) {
ImageButton tempButton = (ImageButton) buttonBoard.getChildAt(i);
tempButton.setVisibility(View.INVISIBLE);
buttonBoard.addView(yourImageButtonHere, i); //adds a new ImageButton in the same cell you are removing the old button from
buttonBoard.removeView(tempButton);
}
This approach should also prevent the GridLayout from rearranging where the children are. I believe the default behavior if you delete a child view is that the GridLayout will re-order the children so there is not empty cell at the beginning of the grid. I hope that makes sense.
There is so much wrong with this approach.
Mainly you don't have to create the ImageButtons manually and add them to the GridLayout. That is what recycled views such as GridView or RecyclerView are for. In fact you should use those to avoid OutOfMemoryError from having too much images in your layout.
But also you cannot just call setId(i) in the for loop. Android holds many ids already assigned and you can never be sure whether the id is safe. (Unless you use View.generatViewId())
And since you only want to remove all views added to your GridLayout why don't you just call removeAllViews() on the buttonBoard?

Updating LinearLayout from other class in Android

I have a class which uses other classes to build up a FrameLayout. One is for Navigation through a building, the other for displaying schematics with sensors of it, and the other one to display sensordata. I build up the whole frame one time, and want to make the sensordata visible in the sensorview part of the frame. Lets say I have 5 sensors, and when I click on one the sensorview shows up the sensordata. I could just make 5 sensorviewframes on top of each other, initiating them invisible, and just make the one visible which was selected via a click on a sensor.
I wanted to ask, is it possible to change the LinearLayout containing the TextViews in a different class with an update method?
I already tried it, but with my code it doesn't work at the moment.
public static SensorBar Create_SensorBar_Layout(Context myContext, ObjectStructure objStruct, ObjectView objView, List<SensorDevice> listofCurrentSensordevices)
{
// Init
LinearLayout SensorBarLinearLayout = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBar = new LinearLayout.LayoutParams(
200, 653);
layoutParamsSensorBar.setMargins(5, 5, 5, 5);
SensorBarLinearLayout.setOrientation(LinearLayout.VERTICAL);
SensorBarLinearLayout.setLayoutParams(layoutParamsSensorBar);
SensorBarLinearLayout.setBackgroundResource(R.drawable.window_frame);
SensorBarLinearLayout.setPadding(4,4,4,4);
LinearLayout SensorBarData = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBarData = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
SensorBarData.setOrientation(LinearLayout.VERTICAL);
SensorBarData.setLayoutParams(layoutParamsSensorBarData);
//--- Button Headline ---
Button buttonNavBarHeadline = new Button(myContext);
buttonNavBarHeadline.setText("Sensordata");
buttonNavBarHeadline.setTextColor(Color.BLACK);
buttonNavBarHeadline.setBackgroundResource(R.layout.mainview_window_headline);
buttonNavBarHeadline.setTextAppearance(myContext, R.style.headline3);
//Layout buildup
SensorBarLinearLayout.addView(buttonNavBarHeadline);
SensorBarLinearLayout.addView(SensorBarData);
return new SensorBar(SensorBarLinearLayout, SensorBarData);
}
This is the Sensorbar, and I want to have the LinearLayout SensorBarData to be dynamically swapped out by clicking on the sensorbuttons.
public void updateSensorBar(Context myContext, ObjectStructure objStruct, List<SensorDevice> listofCurrentSensordevices, int activeSensor)
{
LinearLayout linearlayoutSensorvalueTextviews = new LinearLayout(myContext);
... (additional Textviews for Sensordata, which get added with addview())
setSensorBarData(linearlayoutSensorvalueTextviews);
}
This is used by an OnClick event.
public void setSensorBarData(LinearLayout SensorBarData) { this.dataSensorBar = SensorBarData; }
This is used by the updateSensorBar to update the LinearLayout.
I would be glad for any help.
Define an interface and use a callback to let the activity know that a sensor has been updated.
public Interface SensorUpdatedListener {
void onSensorUpdated();
}
In your SensorBar class.
ArrayList<SensorUpdatedListener > listeners = new ArrayList<SensorUpdatedListener >();
...
public void setSensorUpdatedListener(SensorUpdatedListener listener){
listeners.add(listener);
}
In your sensor bar update method:
for (SensorUpdatedListener listener:listeners){
listener.onSensorUpdated();
}
In your Activity:
public class Test extends Activity implements SensorUpdatedListener {
...
#Override
public void onCreate(Bundle savedInstanceState)
{
...
sensorBar.setSensorUpdatedListener(this);
...
}
public void onSensorUpdated(){
// do whatever you need to do
}
You could improve the SensorBar class by adding removeSensorUpdatedListener and checking that you do not add the same listener twice in setSensorUpdatedListener.

Creating texts and buttons with listeners successively?

I will try to explain my problem. The code below as you can see try to add some textviews and buttons as the array get from another class.
public class Breakfast extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
ScrollView sv = new ScrollView(this);
LinearLayout ll = new LinearLayout(this);
sv.addView(ll);
if (extras != null) {
String food[]=extras.getStringArray("food");
String foodCateg[]=extras.getStringArray("foodCateg");
int K=0;
for (int i = 0; i < food.length/3; i++) {
TextView foodDay = new TextView(this);
foodDay.setText("Day "+ (i+1));
ll.addView(foodDay);
for (int j=K;j<K+3;j++){
Button contfood= new Button(this);
contfood.setText(food[j]);
ll.addView(contfood);
}
K=K+3;
}
this.setContentView(sv);
}
}
My question is how can I know what of this buttons are clicked on the screen?? Because in the case of what one of them are clicked (getting the text that have write before), I will do something or other thing.
ahhhhhhhhhhhhhhhhh yes I know how to do a ListActivity. But first I think in doing by hand because I don´t think how to symplify this...
Thank you for the answers of trying to build with everything a listview and then the method OnListItemClick, but I think that isn´t the solution.
I said that because when I insert the day for example (I Don´t put hear all the code...) but I do .setgravity .setSize .setbackgroundResource etc. And with the food for that day I use a diferent .setgravity and more parameters. So I think that with listview everything would have the same specifications... and that´s what I don´t like.
so... to know what button is pressed on the screen?
You could use contfood.setId(i) and work your way from there.
But what you are doing looks like you really want to create a ListActivity and use it's OnItemClickListener.
What you should do is put an id to each button "contfood". And then when you click on a button retrieve the id back to do the action you want.
Another way is to create the button and attach the method public void onClick(View view):
for (int j=K;j<K+3;j++){
Button contfood= new Button(this);
contfood.setText(food[j]);
ll.addView(contfood);
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(), xxx.class);
startActivityForResult(myIntent, 0);
}
}
and add the parameters within the method.

Categories

Resources