Reputation: 1291
My goal is to pull three JSON Objects
from an adapter and display them as three text views in one list item
. It should look like this when only one set of objects in present:
Instead it's showing this:
I can't see anything wrong in my XML or adapter. (Shown Below) What can cause the textviews to split into more list items than desired like this?
list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:padding="2dp"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="80dp"
android:layout_height="wrap_content"
android:id="@+id/outer"
android:padding="3dp"
android:background="#08445e"
android:layout_toLeftOf="@+id/button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<TextView
android:id="@+id/textViewRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Room "
android:textColor="#fff"
android:layout_alignParentLeft="true"/>
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Time: "
android:layout_alignParentRight="true"
android:textColor="#fff" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/inner"
android:background="#d1d1d1"
android:layout_below="@+id/outer"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/button"
android:layout_toStartOf="@+id/button">
<TextView
android:id="@+id/textViewRequest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="#000"
android:textSize="20sp"
android:layout_centerHorizontal="true" />
</RelativeLayout>
<Button
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#dc2f2f"
android:id="@+id/button"
android:text="Mark Done"
android:textColor="#fff"
android:textAllCaps="false"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/inner"
android:layout_alignParentTop="true" />
</RelativeLayout>
MainAdapter.Java:
package com.example.duncan.recyclerviewproject;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainAdapter extends BaseAdapter {
SharedPreferences preferences;
Context context;
ArrayList<String> arraylist=new ArrayList<>();
public MainAdapter(Context context,
ArrayList<String>arrayList){
this.context=context;
this.arraylist=arrayList;
}
@Override
public int getCount() {
return arraylist.size();
}
@Override
public Object getItem(int i) {
return i;
}
@Override
public long getItemId(int i) {
return i;
}
public class ViewHolder{
Button mark_btn;
public TextView textViewRoom;
public TextView textViewRequest;
public TextView textViewTime;
}
@Override
public View getView(final int position, View row, ViewGroup parent) {
View convertView=row;
final ViewHolder holder;
if(convertView==null) {
holder=new ViewHolder();
LayoutInflater infalInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.custom_layout, null);
holder.mark_btn= (Button) convertView.findViewById(R.id.button);
holder.textViewRoom = (TextView)
convertView.findViewById(R.id.textViewRoom);
holder.textViewRequest = (TextView)
convertView.findViewById(R.id.textViewRequest);
holder.textViewTime = (TextView)
convertView.findViewById(R.id.textViewTime);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.textViewRoom.setText(arraylist.get(position));
holder.textViewRequest.setText(arraylist.get(position));
holder.textViewTime.setText(arraylist.get(position));
holder.mark_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, "Marked complete",
Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
}
MainActivity.java
package com.example.duncan.recyclerviewproject;
import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import me.anwarshahriar.calligrapher.Calligrapher;
public class MainActivity extends AppCompatActivity {
private static final String URL_DATA =
"https://summerproject17.herokuapp.com/api/request/?format=json";
private ListView recyclerView;
private MainAdapter adapter;
private ArrayList<String> listItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (ListView) findViewById(R.id.list);
/* recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));*/
//is the below line newly added?
listItems = new ArrayList<>();
loadRecyclerViewData();
Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "elegantluxpro-mager.ttf", true);
}
private void loadRecyclerViewData(){
StringRequest stringRequest = new StringRequest(Request.Method.GET,
URL_DATA,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray array =
jsonObject.getJSONArray("results");
for(int i = 0; i < array.length(); i++){
JSONObject o = array.getJSONObject(i);
/* ListItem item = new ListItem(
o.getString("room"),
o.getString("request"),
o.getString("unixTime")
);*/
listItems.add(o.getString("room"));
listItems.add(o.getString("request"));
listItems.add(o.getString("room"));
}
Log.e("size",""+listItems.size());
adapter = new
MainAdapter(MainActivity.this,listItems);
recyclerView.setAdapter((ListAdapter) adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", error.getMessage());
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
}
activity_main.xml list view portion:
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list"
android:layout_below="@+id/relativeLayout2">
</ListView>
Note: I asked a similar question a week or so back but this is different in that the structure of the list items has changed and more details have been provided in this question.
Upvotes: 1
Views: 58
Reputation: 27
My goal is to pull 3 JSON Objects from an adapter and display them as 3 text views in one list item. It should look like this when only one set of objects in present:
The list adapter is designed to have a 1 to 1 map with the list that is backing it. Therefore your approach above is somewhat flawed as I understand it. If you want three JSON Objects to be displayed as the three TextView
s of a single list item, you need to translate to another List comprised of (for example) the class ViewHolder
which you defined. Look up ListView
using custom adapter for this. Not sure why ViewHolder
is an internal class, it can simply be a non-public class in the same file.
I can't see anything wrong in my XML
There appear to be some redundancies in your xml layout. What you could do is define a custom layout for your list item, which would have a single RelativeLayout
that has all the three text views and the button (something like this).
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/list_item"
android:padding="3dp">
<TextView
android:id="@+id/textViewRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Room "
android:textColor="#fff"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<Button
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#dc2f2f"
android:id="@+id/button"
android:text="Mark Done"
android:textColor="#fff"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Time: "
android:layout_alignParentTop="true"
android:alignLeft="@id/button"
android:textColor="#fff" />
<TextView
android:id="@+id/textViewRequest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="#000"
android:textSize="20sp"
android:alignBottom="@id/textViewRoom"
android:alignLeft="@id/button"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Or you could use a combination of LinearLayout
and RelativeLayout
. But there is no orientation attribute in RelativeLayout
, so you need to get rid of that as well.
Not sure if this is sufficient to solve the specific problem you were struggling with but I hope it helps.
Upvotes: 2
Reputation: 1770
As adamarta says, the there's a 1 to 1 mapping between your list & what's displayed. 1 item in your ArrayList gives you 1 item in your ListView. A common way of doing this is creating a data model class. It would look like this.
public class RoomItem {
private String room;
private String time;
private String request;
public RoomItem(String room, String request, String time) {
this.room = room;
this.request = request;
this.time = time;
}
public RoomItem() {
}
public String getRoom() {
return room;
}
public void setRoom(String room) {
this.room = room;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
}
Your ArrayList
declaration would change like this.
private ArrayList<RoomItem> listItems;
And you'll have to change the ArrayList
uses in your adapter as well.
Also, in getView()
in the adapter, set the values like this
holder.textViewRoom.setText(arraylist.get(position).getRoom());
holder.textViewRequest.setText(arraylist.get(position).getRequest());
holder.textViewTime.setText(arraylist.get(position).getTime());
In MainActivity, in loadRecyclerViewData()
, replace your 3 current listItems.add(...)
with this.
// create a new data item with the new information
RoomItem item = new RoomItem(o.getString("room"),
o.getString("request"),
o.getString("room"));)
// then add that item to the list
listItems.add(item);
You could also create an empty item then add each field (do either this or the above code, not both)
RoomItem item = new RoomItem();
item.setRoom(o.getString("room");
etc.
As for your layout, if it looks OK in the preview, then it's probably OK. Except... you're replacing the labels (Room & Time) with the values. I don't think you want to do that. I think this is what you need.
<TextView
android:id="@+id/textViewRoomLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Room: "
android:textColor="#fff"
android:layout_alignParentLeft="true"/>
<TextView
android:id="@+id/textViewRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="placeholder"
android:textColor="#fff"
android:layout_toEndOf="@+id/textViewRoomLabel"
android:layout_marginStart="10dp"
/>
<TextView
android:id="@+id/textViewTimeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Time: "
android:layout_toStartOf="@+id/textViewTime"
android:layout_marginEnd="10dp"
android:textColor="#fff" />
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="placeholder"
android:layout_alignParentRight="true"
android:textColor="#fff" />
I haven't built and tested this so I may have missed a couple of small things like needing to make changes for the new ArrayList
etc but I think this is what you need.
Upvotes: 2