Currently I am working on an Android app and use parse as backend where I have created a ListView
of nearby places dynamically. But I face the following design issue: When the user clicks on a place, a view must appear under the clicked item.
And I have faced a problem with grouping the place, as you can see in figure 1, there are many branches for HSBC bank. In which case they are under HSBC.
I have tried expandable ListView before, but it does not give much customization for child view , just simple one.
my BaseAdapter:
import java.util.ArrayList;
import java.util.List;
import com.parse.ParseGeoPoint;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context context;
LayoutInflater inflater;
//ImageLoader imageLoader;
private List<AnywallPost> AnywallPostlist = null;
private ArrayList<AnywallPost> arraylist;
public ListViewAdapter(Context context,
List<AnywallPost> AnywallPostlist) {
this.context = context;
this.AnywallPostlist = AnywallPostlist;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<AnywallPost>();
this.arraylist.addAll(AnywallPostlist);
}
public class ViewHolder {
TextView distance;
TextView name;
}
@Override
public int getCount() {
return AnywallPostlist.size();
}
@Override
public Object getItem(int position) {
return AnywallPostlist.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
final View row=view;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.user_custom, null);
// Locate the TextViews in listview_item.xml
holder.distance = (TextView) view.findViewById(R.id.disView);
holder.name = (TextView) view.findViewById(R.id.nameView);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
// Set the results into TextViews
holder.name.setText(AnywallPostlist.get(position).getText());
holder.distance.setText(AnywallPostlist.get(position).getDis());
//Listen for ListView Item Click
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(context,AnywallPostlist.get(position).getText(), Toast.LENGTH_LONG).show();
}
});
return view;
}
}
.
import com.parse.ParseClassName;
import com.parse.ParseGeoPoint;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.ParseUser;
/**
* Data model for a post.
*/
@ParseClassName("places")
public class AnywallPost extends ParseObject {
public String getText() {
return getString("text");
}
public void setText(String value) {
put("text", value);
}
public String getBank() {
return getString("bank");
}
public void setBank(String value) {
put("bank", value);
}
public ParseUser getUser() {
return getParseUser("user");
}
public void setUser(ParseUser value) {
put("user", value);
}
public String getType()
{
return getString("type");
}
public void setType(String value)
{
put("type",value);
}
public ParseGeoPoint getLocation() {
return getParseGeoPoint("location");
}
public void setLocation(ParseGeoPoint value) {
put("location", value);
}
public String getDis()
{
return getString("dis");
}
public void setdis(String value)
{
put("dis",value);
}
public static ParseQuery<AnywallPost> getQuery() {
return ParseQuery.getQuery(AnywallPost.class);
}
}
.
switch (getItemViewType(position)) {
case 0:
Bank bank = (Bank) getItem(position);
holder.name.setText(bank.name);
String str = String.valueOf(bank.numBranches);
holder.cn.setText(str);
imageLoader.DisplayImage(bank.image,
holder.logo);
Toast.makeText(getActivity(), "img"+bank.image,Toast.LENGTH_LONG).show();
// ... set the image here
// ... set the number of branches here
break;
case 1:
branch = (AnywallPost) getItem(position);
holder.name.setText(branch.getText());
holder.distance.setText(branch.getDis());
holder.b.setText(branch.getbranch());
imageLoader.DisplayImage(branch.getimg(),
holder.logo);
break;
case 2:
branch = (AnywallPost) getItem(position);
holder.name.setText(branch.getText());
holder.distance.setText(branch.getDis());
holder.b.setText(branch.getbranch());
imageLoader.DisplayImage(branch.getimg(),
holder.logo);
// ... set values for all the expanded view widgets too
break;
}
I have used this code to get image from parse and I add it to AnywallPost
ParseFile image = (ParseFile) country.get("image");
AnywallPost map = new AnywallPost();
map.setimg(image.getUrl());
then, I used this code to load the image and it worked fine
imageLoader.DisplayImage(AnywallPostlist.get(position).getimg(),
holder.logo);
答案 0 :(得分:0)
这是我的想法:
你将有两个布局,一个简短的布局,名称为&amp;距离,以及名称为&amp;的扩展名距离加上所有细节。
简短布局的视图类型为0,展开的布局视图类型为1.
单击该项目时,在列表模型中设置一个标志,表示视图已从简短视图切换到长视图。所以你应该看到视图开关。如果单击展开的视图,它将恢复为简短视图。
我没有办法测试这个,但这是我认为代码的样子:
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context context;
LayoutInflater inflater;
//ImageLoader imageLoader;
private List<AnywallPost> AnywallPostlist = null;
private ArrayList<AnywallPost> arraylist;
/** this array holds a flag for each item to show if it is in brief view more or expanded view mode*/
private boolean[] expandedView;
public ListViewAdapter(Context context,
List<AnywallPost> AnywallPostlist) {
this.context = context;
this.AnywallPostlist = AnywallPostlist;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<AnywallPost>();
this.arraylist.addAll(AnywallPostlist);
this.expandedView = new boolean[AnywallPostlist.size()];
}
public class ViewHolder {
TextView distance;
TextView name;
// ... add all your expanded view fields here too
}
@Override
public int getCount() {
return AnywallPostlist.size();
}
@Override
public int getViewTypeCount() {
return 2; // brief & expanded
}
@Override
public int getItemViewType(int position) {
return expandedView[position] ? 1 : 0;
}
@Override
public Object getItem(int position) {
return AnywallPostlist.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
final View row=view;
if (view == null) {
holder = new ViewHolder();
int layout = expandedView[position] ? R.layout.user_custom_expanded : R.layout.user_custom;
view = inflater.inflate(layout, parent, false);
// Locate the TextViews in listview_item.xml
holder.distance = (TextView) view.findViewById(R.id.disView);
holder.name = (TextView) view.findViewById(R.id.nameView);
if (expandedView[position]) {
// ... locate all the expanded view widgets too
}
view.setTag(holder);
} else {
// because the view type is determined by expandedView[position], the correct layout will be recycled here
holder = (ViewHolder) view.getTag();
}
// Set the results into TextViews
holder.name.setText(AnywallPostlist.get(position).getText());
holder.distance.setText(AnywallPostlist.get(position).getDis());
if (expandedView[position]) {
// ... set all the values for your expanded view too
}
//Listen for ListView Item Click
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (expandedView[position]) {
// this is expanded view so toggle it back to brief view
expandedView[position] = false;
} else {
// clear any expanded views elsewhere
expandedView = new boolean[AnywallPostlist.size()];
// toggle brief view to expanded
expandedView[position] = true;
}
// forces the ListView to refresh and convert the brief view into an expanded view and vice versa.
ListViewAdapter.this.notifyDataSetChanged();
// Toast.makeText(context,AnywallPostlist.get(position).getText(), Toast.LENGTH_LONG).show();
}
});
if (expandedView[position]) {
// ... add all your event listeners for the expanded view widgets
}
return view;
}
}
您还可以向视图添加带有展开/折叠指示符的切换按钮,以控制展开/折叠,这样您就不会单击视图上的任何位置进行更改。
如果您愿意,可以使用ExpandableListView
执行此操作,只需更改为ExpandableListAdapter
并稍微改变布局。
答案 1 :(得分:0)
以下是制作异构列表的一些代码:
仔细看看构造函数,看看我是如何通过银行将它们分成一个大的列表来分割它们的。
该列表只是一个Object
数组,因此您可以找出该项目的内容:
如果它是Bank
,那么它就是银行。
如果它是AnywallPost
和expandedView[position] == false
那么它就是一个分支,简短的视图
如果它是AnywallPost
和expandedView[position] == true
那么它就是一个分支,展开的视图
public class Bank {
private String name;
private String image; // maybe this needs to be URL?
private int numBranches;
}
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context context;
LayoutInflater inflater;
ImageLoader imageLoader;
private Object[] masterList;
/** this array holds a flag for each item to show if it is in brief view more or expanded view mode*/
private boolean[] expandedView;
public ListViewAdapter(Context context,
List<AnywallPost> AnywallPostlist) {
this.context = context;
inflater = LayoutInflater.from(context);
/*
* Phase I -- get list of banks and organize the branches by bank
*/
int count = 0;
List<String bankNames = new ArrayList<String>();
List<Bank> banks = new ArrayList<Bank>();
Map<String, Bank> bankMap = new HashMap<String, Bank>();
Map<String, List<AnywallPost>> mappedBranches = new HashMap<String, List<AnywallPost>>();
Bank bank = null;
List<AnywallPost> branches = null;
for (AnywallPost branch : AnywallPostlist) {
// have we started a branch list for this bank?
if (! bankNames.contains(branch.getBank())) { // no we haven't
// remember the bank name
bankNames.add(branch.getBank());
// init a new Bank
bank = new Bank();
bank.name = branch.getBank();
bank.image = branch.getImg(); // if this is URL make image in Bank a URL
banks.add(bank);
bankMap.put(bank.name, bank);
count++;
// create a list for this bank's branches and index it by bank
branches = new ArrayList<AnywallPost>();
mappedBranches.put(branch.getBank(), branches);
} else { // yes we have
// get the bank for this name
// this fixes the problem with the branch counts
bank = bankMap.get(branch.getBank());
// get the branch list we already created for this bank
branches = mappedBranches.get(branch.getBank());
}
// remember the branch for this bank
branches.add(branch);
count++;
// increment the number of branches for this bank
bank.numBranches++;
}
/*
* Phase II -- sort the banks and branches
*/
// ... here you can order the banks by name, branches by distance, etc.
/*
* Phase III -- create the mixed list
*/
int index = 0;
masterList = new Object[count];
for (Bank bank : banks) {
// append a bank to the list
masterList[index] = bank;
index++;
for (AnywallPost branch : mappedBranches.get(bank.name)) {
// append a branch to the list
masterList[index] = branch;
index++;
}
}
this.expandedView = new boolean[count];
}
public class ViewHolder {
TextView distance;
TextView name;
ImageView logo;
// ... add all your expanded view fields here too
}
@Override
public int getCount() {
return masterList.length;
}
@Override
public int getViewTypeCount() {
return 4; // bank brief, bank expanded, branch brief & branch expanded
}
@Override
public Object getItem(int position) {
return masterList[position];
}
@Override
public int getItemViewType(int position) {
if (getItem(position) instanceof Bank) {
return expandedView[position] ? 1 : 0;
}
return expandedView[position] ? 3 : 2;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
final View row=view;
if (view == null) {
holder = new ViewHolder();
int layout = 0;
switch (getItemViewType(position)) {
case 0:
layout = R.layout.bank_brief;
break;
case 1:
layout = R.layout.bank_expanded;
break;
case 2:
layout = R.layout.branch_brief;
break;
case 3:
layout = R.layout.branch_expanded;
break;
}
view = inflater.inflate(layout, parent, false);
switch (getItemViewType(position)) {
case 0:
holder.name = (TextView) view.findViewById(R.id.nameView);
break;
case 1:
holder.name = (TextView) view.findViewById(R.id.nameView);
// ... locate all the bank expanded view widgets too
break;
case 2:
holder.name = (TextView) view.findViewById(R.id.nameView);
holder.distance = (TextView) view.findViewById(R.id.disView);
break;
case 3:
holder.name = (TextView) view.findViewById(R.id.nameView);
holder.distance = (TextView) view.findViewById(R.id.disView);
// ... locate all the expanded view widgets too
break;
}
view.setTag(holder);
} else {
// because the view type is determined by expandedView[position], the correct layout will be recycled here
holder = (ViewHolder) view.getTag();
}
AnywallPost branch = null;
switch (getItemViewType(position)) {
case 0:
Bank bank = (Bank) getItem(position);
holder.name.setText(bank.name);
imageLoader.DisplayImage(bank.image, holder.logo);
// ... set the number of branches here
break;
case 1:
holder.name.setText(bank.name);
imageLoader.DisplayImage(bank.image, holder.logo);
// ... set the number of branches here
break;
case 1:
branch = (AnywallPost) getItem(position);
holder.name.setText(branch.getText());
holder.distance.setText(branch.getDis());
break;
case 2:
branch = (AnywallPost) getItem(position);
holder.name.setText(branch.getText());
holder.distance.setText(branch.getDis());
// ... set values for all the expanded view widgets too
break;
}
//Listen for ListView Item Click
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (expandedView[position]) {
// this is expanded view so toggle it back to brief view
expandedView[position] = false;
} else {
// clear any expanded views elsewhere
expandedView = new boolean[expandedView.length];
// toggle brief view to expanded
expandedView[position] = true;
}
if (getItem(position) instanceof AnywallPost) { // only for branches
// AnywallPost branch = (AnywallPost) getItem(position);
// Toast.makeText(context, branch.getText(), Toast.LENGTH_LONG).show();
}
// forces the ListView to refresh and convert the brief view into an expanded view and vice versa.
notifyDataSetChanged();
}
});
if (expandedView[position]) {
// ... add all your event listeners for the expanded view widgets
}
return view;
}
}