How do I dynamically generate a RelativeLayout based on a xml layout (posted below)? The relative layouts are being put in a linear layout that is the child of a scroll view.
<RelativeLayout
android:id="#+id/post_0"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<TextView
android:id="#+id/op_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:text="Username" />
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_below="#+id/op_username"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="31dp"
android:layout_marginLeft="31dp"
android:layout_marginTop="15dp"
app:srcCompat="#android:drawable/btn_star_big_on"
tools:srcCompat="#android:drawable/btn_star_big_on" />
</RelativeLayout>
Let's suppose that you've all the Images and their TextView's texts in your Database, then create a RecyclerView (if there are a relatively huge number of items) or a simple ListView, and then create a CustomAdapter class to add your RelativeLayout to your main ListView/ ScrollView/ RecyclerView.
To completely implement this first you need to have an Item class which can store a user's Username and Image ( please note that you need to pass Image URI as a string) in an Object.
public class Items {
private final int id;
private final String image;
public Items(int id,String image){
this.name=name;
this.image=image;
}
//Include all the Getters and Setters here
}
Then assuming you've all your elements into an ArrayList<Items>, then you need to implement an Adapter class, called CustomAdaper which extends ArrayAdapter and need to write a function for getView to get a particular view to fill in your ScrollView/RecyclerView/ListView
I've found a link to help you implement a CustomAdapter here.
And finally in the MainActivity, you've to add few lines,
final ListView listView = (ListView) findViewById(R.id.list_view); //name of list view file
final ArrayList<Items> arrayList = dbHelper.retrieveFromDB(); // Name of the Database class and the function to retrieve all the elements into an ArrayList in that class
CustomAdapter adapter = new CustomAdapter(this /* The current Context */, R.layout.list_item, arrayList); // Create an object of custom adapter initialize it with the desired data (in this case the arrayList) and the layout required ( layout mentioned in the question)
listView.setAdapter(adapter);
If it is a dynamic list that can have a large number of items use a recyclerview and place that relative layout inside a cardview.
If the dynamic list has a maximum potential number of items that are also few in number, you could add the relative layout and hide them, then populate and then show them as needed, but i advice you lean toward the former.
Related
I am trying to spawn some XML view for each instance of POJO data objects in a list, similar to how a ListView would do it, but it's not a ListView actually, but an empty LinearLayout instead, which is inside a ScrollView below other Fragment's content.
This is the item.xml file I want to inflate for each element of the list:
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/item_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="0dp"
android:text="ITEM_LABEL"
android:textSize="16sp" />
<TextView
android:id="#+id/item_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:text="ITEM_TEXT_1"
android:textSize="14sp" />
<TextView
android:id="#+id/item_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:text="ITEM_TEXT_2"
android:textSize="14sp" />
</LinearLayout>
...and this is the way I am trying to inflate it in the Fragment Java class:
public class MyFragment extends Fragment {
// we skip the "boilerplate"...
// [...]
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.my_fragment, container, false);
// XXX I use LiveData<> with Room to retrieve
// rows from DB inside POJO objects
LiveData<List<MyItem>> items_list = itemsViewModel.getItemsByParentId(some_id);
// The "parent" is not relevant, let's just
// focus on the List
LinearLayout items_list_layout = view.findViewById(R.id.items_list_layout);
items_list.observe(getActivity(), new Observer<List<MyItem>>() {
#Override
public void onChanged(List<MyItem> items) {
// Just in case, (maybe I'm wrong but) I think otherwise
// previous inflated objects remain on loading this same
// fragment for another parent
objs_list_layout.removeAllViews()
for (MyItem item : items) {
// XXX Here I inflate item.xml as a LinearLayout
LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout);
// XXX ... and try to change it's TextView children
TextView item_label = obj_item.findViewById(R.id.item_label);
item_label.setText(item.item_label);
TextView item_text1 = obj_item.findViewById(R.id.item_text1);
item_text1.setText(item.item_text1);
TextView item_text2 = obj_item.findViewById(R.id.item_text2);
item_text2.setText(item.item_text2);
}
}
});
}
}
This works well when the method getItemsByParentId only return a List with one only MyItem instance. But when the query returns more than one Item, it works unexpectedly wrong:
The first inflated item.xml element (or the one shown first, on top) has its TextViews modificated as expected, but for the last item in the list.
The rest of "inflated elements" have not been changed (it shows just ITEM_LABEL, ITEM_TEXT1 and ITEM_TEXT2 hardcoded strings as they are in the template XML file).
However, it inflates the XML template items.size() times as I planned.
Actually, the objective is that each "inflated item.xml" is edited with attributes of each corresponding Item. Just like a ListView would do, but without using ListView at all, because the goal is, actually, bloating an existing ScrollView (the main container in the fragment) that shows other different Views outside of the "LinearLayout" dedicated to generate this "list". How can I make it work without these errors?
View.inflate imho is a not the clearest method ) it returns the root View of the inflated hierarchy. If root was supplied, this is the root View; otherwise it is the root of the inflated XML file.
So obj_item is not an item view. It is an items_list_layout view. Inside it you find R.id.item_label in first item view and set it. Other item views are not initialized because findViewById returns first item it found.
Change this part:
LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout);
to
LinearLayout obj_item = LayoutInflator.from(view.getContext()).inflate(R.layout.item, items_list_layout, false);
I prefer to add child views explicitly to make code more readable. So and add this code to add item view to parent layout:
items_list_layout.addView(obj_item)
I have a Java class and two XML files which are basically just a side by side listView which takes in some values. I want to put a header or a text view above each list view ( they should stay side by side ) however every time I try to add a textView the whole project messes up and following online instructions is not working to implement a header.
public class Leaderboard extends AppCompatActivity {
private ListView UsernameList;
private ListView ScoreList;
LocalDatabase localDatabase;
/** Called when the activity is first created */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leaderboard);
ArrayAdapter<String> listAdapter;
ArrayAdapter<Integer> list2Adapter;
//Find the ListView resources
UsernameList = (ListView) findViewById(R.id.UsernameList);
ScoreList = (ListView) findViewById(R.id.ScoreList);
//Create and populate the list of usernames.
//This is where the information from the Database would need to be entered. and the String[] removed
String[] usernames = new String[]{"Andy", "Marie", "George"};
ArrayList<String> usernameList = new ArrayList<String>();
usernameList.addAll(Arrays.asList(usernames));
//Create and populate the list of scores
//This is where the information from the Database would need to be entered. and the Integer[] removed
Integer[] scores = new Integer[]{7, 4, 1};
ArrayList<Integer> scoreList = new ArrayList<Integer>();
scoreList.addAll(Arrays.asList(scores));
//adds the users details to the leaderboard
localDatabase = new LocalDatabase(this);
Contact contact = localDatabase.getLoggedInUser();
//Set a string to have the value of the users name.
String s = contact.name;
//Create Array Adapter using the username list
listAdapter = new ArrayAdapter<String>(this, R.layout.activity_row, usernameList);
//Add more users
listAdapter.add(s);
//Set the Array Adapter as the ListView's adapter
UsernameList.setAdapter(listAdapter);
//Create Array Adapter using the username list
list2Adapter = new ArrayAdapter<Integer>(this, R.layout.activity_row, scoreList);
//Add more users
list2Adapter.add(0);
//Set the Array Adapter as the ListView's adapter
ScoreList.setAdapter(list2Adapter);
}
}
Then the two xml files
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#color/colorPrimaryDark"
android:id="#+id/rowTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:textStyle="bold"
android:padding="10dp"
android:textSize="16sp">
</TextView>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:background="#color/colorPrimaryDark"
android:layout_height="fill_parent"
android:padding="20dp"
android:orientation="horizontal"
tools:context=".Leaderboard">
<ListView
android:id="#+id/UsernameList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight=".60"
android:drawSelectorOnTop="false"
android:headerDividersEnabled="false">
</ListView>
<ListView
android:id="#+id/ScoreList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight=".40">
</ListView>
</LinearLayout>
Try encapsulating the two TextViews in a LinearLayout. The linear Layout should span the entire width (match_parent), but only be as high as need be; wrap_content.
What you then want to do to have them neatly divided amongst the width of the screen, is, first off, set the LinearLayout orientation to horizontal. Then, you make the width of and both TextViews 0dp (that's right, 0dp), and their height wrap_content. Then, give both TextViews a weight of 1. The views now both take up half the space (in width) of the LinearLayout. Finally, centre the TextViews for a good looking header.
Ive kept it very broad and non-codey, but I think you should be able to google all the concepts explained above if you run into any trouble. If you really cant figure it out,i'll help you out in the comments.
I'm new to android so please be tolerant to my lack of knowledge.
My app is taking photos and saving them to Bitmap ArrayList, it works, i tested it, photos are displayable using ImageViews. Everything responsible for taking pictures looks like this:
//declaration
List<Bitmap> bmpList = new ArrayList<Bitmap>();
//onClick method of button for takin pics
public void takePic(View view){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == 0){
Bitmap image = (Bitmap) data.getExtras().get("data");
bmpList.add(image);
adapter.notifyDataSetChanged(); //more about my adapter and stuff below
}
}
I also have ListView, i'm extending ListActivity instead of just Activity becouse i found that working solution for dynamic String ArrayList in web. XML declaration of ListView: (with that method i don't have to declare it in the Java code)
<ListView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/photoButton"
android:id="#android:id/list">
</ListView>
I also use Bitmap adapter:
ArrayAdapter<Bitmap> adapter;
and then initialize it inside of onCreate method:
adapter = new ArrayAdapter<Bitmap>(this, R.layout.item, bmpList);
setListAdapter(adapter);
item.xml is the problem i have. I don't know how to create working ListView item that contains ImageView capable of displaying my Bitmap ArrayList elements preferably on the left. I tried adding just a ImageView but app crashes after saving the photo. My go-to functionality is having photo on the left, short description in the middle and ratingbar on the right, clicking on item takes user to another Activity where one can modify the description and rating, also displaying photo in full size. Some kind of hint will go a long way! Thank you in advance!
You should implement a custom adapter, to work with your images, and inflate your list. You can find useful tutorial here, which describes how to use listViews and adapters, and how to create your own list items.
You can create your custom XML item layout like usual layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/icon"
android:layout_width="22px"
android:layout_height="22px"
android:layout_marginLeft="4px"
android:layout_marginRight="10px"
android:layout_marginTop="4px"
android:src="#drawable/ic_launcher" >
</ImageView>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="20px" >
</TextView>
</LinearLayout>
But for adding images to it, you must implement your own custom adapter.
Is there a way to set the viewable item count for a listview? or am I obliged to set the height for the listview?
For instance, I got a list that includes 9 items. I only want 4 of them to appear at first. Then user needs to scroll to see other items.
list_anlam.xml
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="1dp"
android:background="#android:color/darker_gray" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/title_popup_hikayeoku" />
<EditText android:id="#+id/kelime_text"
android:inputType="text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ListView android:id="#+id/list_anlam"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
<Button
android:id="#+id/button_sec"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/button_popup_hikayeoku" />
</LinearLayout>
list_item.xml :
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:padding="10dp" />
Where I fill items into listview : HikayeOkuActivity.java is
String[] anlamlar = null;
anlamlar = MainActivity.dbM.ilkAnlamGetir(selectedText);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item,anlamlar);
anlamList.setAdapter(adapter);
popupWindow.showAsDropDown(mainLayout, touchedX,touchedY);
Yes, you need to get the height of the listview. In your onCreate you do something like:
listview.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
height = listView.getHeight();
}
In the getView method of your adapter you then use the height divided by four to set the height of each list item.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
View rowView = inflater.inflate(R.layout.item_layout, parent, false);
rowView.setMinHeight(height/4);
return rowView;
}
Now this should preferably be done with a ViewHolder, but that's not the topic here.
Basically, the height of each view must be 1/4 of the height of your ListView. If you want to support all device resolutions, you have to calculate it. If you need more info about that, add a comment and I will explain it in detail.
Important for details, what kind of Adapter are you using for your ListView?
Correct me if I'm wrong, but..
you could also use an android:WEIGHTSUM and android:WEIGHT parameters in your xml layouts. Set android:weightsum=1 for parent view (your ListView) and android:weigth=0.25 for child views (layout of ListView items). In this case you don't have to calculate heights of your viewables.
I'm having a problem with a custom ListView I am using in the ListActivity of my application. My problem is that all TextView items added to the ListView through an ArrayAdapter show up with a gray bar above them. I would include an image of the displayed ListView, but am unable since I do not have a reputation of 10 required by the stackoverflow site.
The layout file (index.xml) used to produce the ListView is defined as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical" >
<ListView
android:divider="#color/mg_red"
android:dividerHeight="1sp"
android:id="#android:id/list"
android:layout_height="fill_parent"
android:layout_width="fill_parent" />
<TextView
android:title="text_view"
android:background="#drawable/listitemback"
android:cacheColorHint="#drawable/listitemback"
android:id="#+id/listItem"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10sp"
android:textColor="#color/listitemtext"
android:textSize="16sp" />
</LinearLayout>
The ListActivity code used to display the list is as follows:
public class IndexListActivity extends ListActivity
{
private ListView m_listView = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
try
{
if (MGApplication.DEBUG_BUILD)
Log.i("TMG", "IndexListActivity.onCreate");
super.onCreate(savedInstanceState);
// Get our global data object.
MGApplication mgApp = (MGApplication) getApplication();
// Set view layout
SetContentView(R.layout.index);
// Get references to our ListView and AdView objects
m_listView = (ListView) findViewById(android.R.id.list);
// Create a new ArrayAdapter object that will be used to initialize
// the underlying ListView object.
ArrayAdapter<String> aa = new ArrayAdapter<String>(this, R.layout.index,
R.id.listItem,
mgApp.m_strAZRhymeNames);
// Assign array adapter
m_listView.setAdapter(aa);
}
catch (Exception e)
{
}
return;
}
}
Any help is greatly appreciated as I am at my wits end with this issue. I think I've tried every suggestion I could find on the web and I am unable to remove the gray bar.
Thank You,
Bob
you have to set this property in test.xml file with.
<ListView
android:id="#+id/listview_middle"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="1dip"
android:layout_weight="1"
android:background="#ffffff"
android:cacheColorHint="#android:color/transparent"
android:choiceMode="singleChoice"
android:scrollingCache="false" />
and set some property in listview object.
lv.setVerticalFadingEdgeEnabled(false);
In my side that's work perfect.