I know that there were a lot of questions like this one, but I haven't been able to find the answer I'm looking for...
I'd like to dynamically create some TextView in an already existing ScrollView. I've done something that I thought would have been okay, but the app stops when it comes to this fragment?
I can't put the whole project because the files are numerous, but here are the concerned .java and .xml:
NotesPageFragment.java
package com.a3m.Controllers.Fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.a3m.Controllers.ui.Controler;
import com.a3m.Controllers.core.Task;
import com.a3m.R;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
public class NotesPageFragment extends Fragment {
private Controler controler;
private ScrollView mScrollView;
public static NotesPageFragment newInstance() {
return(new NotesPageFragment());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_notes_page, container, false);
this.controler = Controler.getInstance();
this.mScrollView = v.findViewById(R.id.fragment_page_notes_scrollview);
//addNotes(notes,getAllTasks());
addNotes(v, getAllTasks());
return v;
}
public ArrayList<Task> getAllTasks()
{
/*
** ici le code qui se connecte à la bdd et retourne toutes les tasks disponibles
*/
ArrayList<Task> tasks = new ArrayList<>();
ArrayList<String> n =new ArrayList<>();
n.add("detail1");
n.add("detail2");
n.add("detail3");
Task t1=new Task(0,0,null,"t1",0,0,null,0,null,null,n,null);
Task t2=new Task(0,0,null,"t2",0,0,null,0,null,null,n,null);
Task t3=new Task(0,0,null,"t3",0,0,null,0,null,null,n,null);
Task t4=new Task(0,0,null,"t4",0,0,null,0,null,null,n,null);
Task t5=new Task(0,0,null,"t5",0,0,null,0,null,null,n,null);
Task t6=new Task(0,0,null,"t6",0,0,null,0,null,null,n,null);
Task t7=new Task(0,0,null,"t7",0,0,null,0,null,null,n,null);
tasks.add(t1);
tasks.add(t2);
tasks.add(t3);
tasks.add(t4);
tasks.add(t5);
tasks.add(t6);
tasks.add(t7);
return tasks;
}
public void addNotes(View view, ArrayList<Task> tasks) {
Iterator<Task> itr_tasks = tasks.iterator();
Task task;
String taskNote;
while(itr_tasks.hasNext()) {
taskNote = "";
task = itr_tasks.next();
taskNote += task.getName();
Iterator<String> itr_notes = task.getNotes().iterator();
while(itr_notes.hasNext()) {
taskNote += "\t\t\t" + itr_notes.next() + "\t\t\t";
}
final TextView taskNotes = new TextView(getActivity());
taskNotes.setText(taskNote);
mScrollView.addView(taskNotes);
}
}
}
fragment_notes_page.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_page_news_rootview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EDD9CF"
android:contentDescription="NotesPage"
android:gravity="center"
tools:context="com.a3m.Controllers.Fragments.NotesPageFragment">
<ScrollView
android:id="#+id/fragment_page_notes_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="#dimen/nav_header_marginLeft">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView2"
android:layout_width="match_parent"
android:layout_height="171dp"
android:src="#android:drawable/ic_menu_info_details" />
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="65dp"
android:text="Notes"
android:textAlignment="center"
android:textAllCaps="false"
android:textSize="30sp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</ScrollView>
</LinearLayout>
I'm aware that the IDs in the .xml aren't really good, but I'll improve them later...
If someone has an idea or can show me were the answer is, I'll gladly accept this help!!
ScrollView and all it's relatives that scroll the content (i.e. NestedScrollView) allow only for one child. You cannot add new views directly to ScrollView if it already has one child view.
Quote from java doc to ScrollView class:
/**
* A view group that allows the view hierarchy placed within it to be scrolled.
* Scroll view may have only one direct child placed within it.
* To add multiple views within the scroll view, make
* the direct child you add a view group, for example {#link LinearLayout}, and
* place additional views within that LinearLayout.
...
*/
And if you look inside of the class you will find that it overrides all addView methods:
To fix the issue what you need to do is to add id to your LinearLayout and insert new views into it.
I'd recommend changing it all to RecyclerView + Adapter.
Official tutorials from Google on how to use RecyclerView and Adapters
First of all, I wanna say I've been seeking for an answer on the Forum and I found didn't match for what I wanted. Basically, what I want is: when the user clicks on one of the images previously "specified" on the .xml file, a new image is displayed on the center of the screen that is not "specified" on the .xml file. I wrote "specified" cause idk if it's the correct way to refer to this.
EDIT: there was no need to not specify the image previously, all I needed was to set "gone" for visibiity. This code is working exactly how I wanted (ty guys):
Main.java
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.Toast;
public class Principal extends Activity {
ImageView cuia1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_principal);
cuia1 = (ImageView) findViewById(R.id.cuia1);
cuia1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ImageView cuia1grande = (ImageView) findViewById(R.id.cuia1grande);
cuia1grande.setVisibility(1);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.principal, menu);
return true;
}
}
activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:id="#+id/tableLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:shrinkColumns="*"
android:stretchColumns="*">
<TableRow
android:id="#+id/tabelaCuias"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center">
<TextView
android:id="#+id/selecionaCuia"
android:text="Selecione a cuia"
android:textStyle="bold">
</TextView>
<ImageView
android:id="#+id/cuia1"
android:src="#drawable/cuia1">
</ImageView>
<ImageView
android:id="#+id/cuia2"
android:src="#drawable/cuia2">
</ImageView>
<ImageView
android:id="#+id/cuia3"
android:src="#drawable/cuia3">
</ImageView>
<ImageView
android:id="#+id/cuia4"
android:src="#drawable/cuia4">
</ImageView>
</TableRow>
</TableLayout>
<ImageView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_centerInParent="true"
android:visibility="gone"
android:id="#+id/cuia1grande"
android:src="#drawable/cuia1grande">
</ImageView>
Is there any reason you don't want to "specify" the image in your layout file? You could place it there and not display it (visibilty="gone"), and then show/hide it when you deem fit.
Here's what I'd do:
Make your layout a RelativeLayout instead of a TableLayout (this will make things easier for showing the image in the center)
Place your TableLayout within the wrapping RelativeLayout
Define an ImageView as the last child within the wrapping RelativeLayout, set centerInParent="true", visibilty="gone"
In your onClick method, simply set its visibility as visible.
If you really don't want to define the ImageView in the layout, then you can create it programmatically:
Follow the same steps 1-2 as before
Capture the reference to the wrapping RelativeLayout in the code
In the onClick method, create the ImageView programatically, specifying the centerInParent="true" via the code (let me know if you want an example on how to do this & I'll edit the answer with a code sample).
Add the new view to the RelativeLayout via myRelativeLayout.addView(myImageView);
Hope this helps :)
public class Principal extends Activity {
ImageView cuia1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_principal);
cuia1 = (ImageView) findViewById(R.id.cuia1);
//set invisible
cuia1 .setVisibility(View.INVISIBLE);
cuia1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//show image on the center of screen
//set image
cuia1.setImageResource(R.drawable.cuia1);
// set visible
cuia1 .setVisibility(View.VISIBLE);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.principal, menu);
return true;
}
}
import import android.view.View;
Cheerz!
I am using linear layout to get the message with image from .net server.
when the new message is come the position of the layout is increased and the new message is added to the top of the layout one by one.
the problem is when the new message will come,the new message is added to layout suddenly.
I want to apply animation to the layout and make my app like when the new message is come the message is added to the layout slowly. means the previous messages move down slowly and new message is added top of the layout.
Use android:animateLayoutChanges on the LinearLayout that shall hold the data. This will trigger an animation when adding new content. It starts by moving the old data down making room for more content. Then follows a second step where the new data will fade into the free space.
Example code
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/baseLL"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!-- button used to add data -->
<Button
android:layout_width="192dip"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Add Content"
android:onClick="onAddContentClick" />
<!-- button used to remove data -->
<Button
android:layout_width="192dip"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Remove Content"
android:onClick="onRemoveContentClick" />
<!-- data will be added to this LinearLayout at run time -->
<LinearLayout
android:id="#+id/dataLL"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:animateLayoutChanges="true"
>
</LinearLayout>
</LinearLayout>
basicanimation.java
package com.test.animation.basic;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class BasicAnimationActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onAddContentClick(View v) {
LinearLayout dataLL = (LinearLayout) findViewById(R.id.dataLL);
int dataCount = dataLL.getChildCount();
TextView newDataTV = generateData(dataCount);
dataLL.addView(newDataTV, 0);
}
public void onRemoveContentClick(View v) {
LinearLayout dataLL = (LinearLayout) findViewById(R.id.dataLL);
if (dataLL.getChildCount() > 0) {
dataLL.removeViewAt(0);
}
}
private TextView generateData(int dataCount) {
TextView TV = new TextView(this);
TV.setText("Data " + dataCount);
TV.setLayoutParams(new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
return TV;
}
}
I'm trying to get a simple onClick to fire from an ImageButton - it seems like a simple enough task, but I'm obviously missing something here.
Here is my java file:
package com.jlbeard.android.testapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.Toast;
public class testapp extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//handle the button press
ImageButton mainButton = (ImageButton) findViewById(R.id.mainButton);
mainButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//show message
Toast.makeText(testapp.this, "Button Pressed", Toast.LENGTH_LONG);
}
});
}
}
Here is my layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="#+id/whereToEat"
android:src="#drawable/where_to_eat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="8px"
/>
<ImageButton
android:id="#+id/mainButton"
android:src="#drawable/main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="#null"
android:clickable="true"
android:onClick="mainButtonClick"
/>
</RelativeLayout>
It seems to me that I'm missing something simple... but can't seem to figure it out. Thanks!
You didn't run show() method on Toast object. Very common mistake :-)
You also might have a problem due to the manifest setting onClick
android:onClick="mainButtonClick"
If mainButtonClick exists on post 1.5 devices it may be called instead, overriding the one you're setting in code
In my case, the imageButton was displayed behind a list. Because the list was empty, the ImageButton was seen but onClick was never fired.
Adding android:elevation="5dp" in the screen xml solve my problem
Note that if I use Button instead of ImageButton, elevation is not required.
package com.iperetz1.android.testbutton1;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class TestButton extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button test2 = (Button)findViewById(R.id.test2);
test2.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
setContentView(R.layout.test2);;
}
});
Button other = (Button)findViewById(R.id.backmain);
other.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
setContentView(R.layout.main);;
}
});
}
}
main.xls
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
android:id="#+id/widget0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="#+id/test2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test2"
android:layout_x="24px"
android:layout_y="165px"
>
</Button>
</AbsoluteLayout>
test2.xml
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
android:id="#+id/widget0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="#+id/backmain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="backmain"
android:layout_x="24px"
android:layout_y="165px"
>
</Button>
</AbsoluteLayout>
findViewById is a lot simpler than people tend to think it is. It traverses the view hierarchy looking for a view with the given ID. If it's not found, findViewById returns null.
You started by setting the content view to your main layout but later on you tried to findViewById(R.id.backmain). Since there is no view with that ID in your main layout, it returns null. At that point attempting other.setOnClickListener will fail. You will only be able to do this when your button actually exists in the view hierarchy.
There's nothing inherently wrong with dynamically changing your view hierarchy, but you'll have to handle some things differently if you go that route. (Such as when you wire up events to views that don't exist during onCreate like you're trying to do above.)
As #Cristian Castiblanco said, changing the view dynamically is causing the problem, for these kind of scenarios, you have to create separate activities and invoke them using intents and pass data between them using bundles.