I have a problem and I can't solve it. I would like to create poll application. I Create 2 classes :
- Poll which contain user's name, the question and an ArrayList of Choice
- Choice contain the choice and its id.
I would like to display on the home page a list of questions (ArrayList) with the differents choices. I managed to display this list but I have a problem with ArrayList of the class Poll because only the first item is display but I want to display all the list of choice.
POLL CLASS
public class Poll{
String question;
String forename;
ArrayList<Choice> list_choices;
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
public ArrayList<Choice> getListChoice() {
return list_choices;
}
public void setListChoice(ArrayList<Choice> list_choices) {
this.list_choices = list_choices;
}
}
CHOICE CLASS
public class Choice {
int id;
String choice;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getChoice() {
return choice;
}
public void setChoice(String choice) {
this.choice = choice;
}
}
Adapter for Poll
public class CustomListAdapter extends BaseAdapter{
ArrayList<Poll> listPolls;
LayoutInflater layoutInflater;
Context context;
public CustomListAdapter(Context context,ArrayList<Poll> listPolls) {
this.listPolls = listPolls;
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listPolls.size();
}
#Override
public Object getItem(int arg0) {
return listPolls.get(arg0);
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
ViewHolder holder;
if (arg1==null)
{
arg1= layoutInflater.inflate(R.layout.row_list, null);
holder = new ViewHolder();
holder.ForenameView = (TextView) arg1.findViewById(R.id.forename);
holder.QuestionView = (TextView) arg1.findViewById(R.id.question);
holder.ChoiceView = (ListView) arg1.findViewById(R.id.choice);
//tagguer notre objet pour pouvoir le récupérer à la prochaine mise à jour graphique.
arg1.setTag(holder);
}
else
{
holder = (ViewHolder) arg1.getTag();
}
holder.ForenameView.setText(listPolls.get(arg0).getForename());
holder.QuestionView.setText(listPolls.get(arg0).getQuestion());
holder.ChoiceView.setAdapter(new CustomListChoiceAdapter(context, listPolls.get(arg0).getListChoice()));
return arg1;
}
static class ViewHolder {
TextView ForenameView;
TextView QuestionView;
ListView ChoiceView;
}
}
Adapter for choice
public class CustomListChoiceAdapter extends BaseAdapter {
ArrayList<Choice> listChoices;
LayoutInflater layoutInflater;
public CustomListChoiceAdapter(Context context,ArrayList<Choice> listChoices) {
this.listChoices = listChoices;
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listChoices.size();
}
#Override
public Object getItem(int arg0) {
return listChoices.get(arg0);
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
ViewHolder holder;
if (arg1==null)
{
arg1= layoutInflater.inflate(R.layout.row_list_choice, null);
holder = new ViewHolder();
holder.ChoiceView = (TextView) arg1.findViewById(R.id.choice_text);
//holder.IdView = (TextView) arg1.findViewById(R.id.question);
//tagguer notre objet pour pouvoir le récupérer à la prochaine mise à jour graphique.
arg1.setTag(holder);
}
else
{
holder = (ViewHolder) arg1.getTag();
}
holder.ChoiceView.setText(listChoices.get(arg0).getChoice());
notifyDataSetChanged();
//holder.IdView.setText(listChoices.get(arg0).getId());
return arg1;
}
static class ViewHolder {
TextView ChoiceView;
//TextView IdView;
}
}
XML Home page
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:orientation="vertical"
android:id="#+id/LinearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/customborder"
>
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#000000"
>
</ListView>
</RelativeLayout>
</LinearLayout>
XML Poll List
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/forename"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="Medium Text"
android:textColor="#color/blue"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:text="TextView" />
<ListView
android:id="#+id/choice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#000000"
>
</ListView>
</LinearLayout>
</LinearLayout>
XML Choice List
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/choice_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="Medium Text"
android:textColor="#color/pink"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
</LinearLayout>
Activity which display ArrayList
public class debug extends Activity {
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.debugg);
//Récuperation de ListView crée
lv = (ListView) findViewById(R.id.listView1);
ArrayList<Choice> list_choice = new ArrayList<Choice>();
Choice choix = new Choice();
choix.setChoice("choix 1");
list_choice.add(choix);
choix = new Choice();
choix.setChoice("choix 2");
list_choice.add(choix);
ArrayList<Poll> resultats = new ArrayList<Poll>();
Poll newsData = new Poll();
newsData.setListChoice(list_choice);
newsData.setForename("Paul");
newsData.setQuestion("Question 1");
resultats.add(newsData);
newsData = new Poll();
newsData.setListChoice(list_choice);
newsData.setForename("Laetitia");
newsData.setQuestion("Question 2");
resultats.add(newsData);
lv.setAdapter(new CustomListAdapter(this, resultats));
}
}
Man, the one and origin solution is:
Set your parent ListView item WRAP_CONTENT height. Next, set fixed height of your included ListView item. Then in getView() method set the height of your included ListView the height equals to parent_array_list.size() * child_list_view_item_height. It might be help you.
Code example:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) (listPolls.size() * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, child_list_view_item_height, displayMetrics)));
holder.ChoiceView.setLayoutParams(params);
Related
I have populated weight conversion functionality on listview using string array. I want to change the values of each entity when new value is typed by the user on any entity i.e KG, Pound and Gram. But addTextChangedListener is not responding properly and values are getting wrong on each EditText.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
convAdapter adapter = new convAdapter(MainActivity.this);
ListView list = findViewById(R.id.unitc_list);
list.setAdapter(adapter);
}
}
convAdapter.java
public class convAdapter extends BaseAdapter {
static TextWatcher watcher=null;
DecimalFormat format = new DecimalFormat("0.########");
private String unitWeight[] = {"Pound","Kilogram","Gram"};
private static String unitWeightValue[] = {"2.204","1","1000"};
private String unitWeightValueUpdated[] = unitWeightValue;
private static Activity activity;
private static LayoutInflater inflater=null;
public convAdapter(Activity a) {
activity = a;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return unitWeight.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView==null){
convertView = inflater.inflate(R.layout.unit_row, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.txtItem.setText(unitWeight[position]);
viewHolder.etValue.setText(format.format(((double) Math.round(10000*Double.parseDouble(unitWeightValueUpdated[position]))/10000.0)));
viewHolder.txtItem.setTag(position);
viewHolder.etValue.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void afterTextChanged(Editable s) {
if(unitWeight[position].equals("Kilogram")){
int i = 0;
for(String pos: unitWeightValue ){
unitWeightValueUpdated[i] = format.format(((double) Math.round(Double.parseDouble(pos)*Double.parseDouble(String.valueOf(viewHolder.etValue.getText())))));
i++;
}
}else{
int i = 0;
for(String pos: unitWeightValue ) {
unitWeightValueUpdated[i] = String.valueOf(Double.parseDouble(viewHolder.etValue.getText().toString())* Double.parseDouble(pos) /
Double.parseDouble(unitWeightValueUpdated[i]));
i++;
}
}
}
});
return convertView;
}
private class ViewHolder {
TextView txtItem;
EditText etValue;
public ViewHolder(View view) {
txtItem = view.findViewById(R.id.tvUnitName);
etValue = view.findViewById(R.id.etValue);
}
}
}
unit_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:paddingLeft="5dp"
android:weightSum=".2"
android:orientation="horizontal">
<TextView
android:id="#+id/tvUnitName"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center|left"
android:text="Unit"
android:textSize="16sp"
android:paddingLeft="5dp"
android:layout_weight=".1"
/>
<EditText
android:id="#+id/etValue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="right"
android:text="100"
android:inputType="numberDecimal"
android:textSize="16sp"
android:paddingRight="15dp"
android:layout_margin="5dp"
android:layout_weight=".1"
/>
</LinearLayout>
activity_main.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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ListView
android:id="#+id/unitc_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Problems:
addTextChangedListener are being called multiple times unnecessarily
Values are not updating properly.
Thanks in advance for the help.
Error Shown:
Attempt to invoke virtual method 'void android.widget.GridView.setAdapter(android.widget.ListAdapter)' on a null object reference.
The error surface at the gridView.setAdapter(adapter); but am able to print response from API only to pass it to the adapter for layout to handle the display.
Am suggesting converting the Model Class into a list of array of which is not actually going my way.
Have tried modelName.toArray() and many others.
Thank you as i await your response.
My Model Class
public class MensWear {
private int id, user_id;
private String first_wear;
public MensWear(int id,int user_id,String first_wear) {
this.id = id;
this.user_id = user_id;
this.first_wear = first_wear;
}
public int getId() {
return id;
}
public int getUser_id() {
return user_id;
}
public String getFirst_wear() {
return first_wear;
}
}
My Base Adapter Class
public class PhoneAdapter extends BaseAdapter {
private Context context;
private List<MensWear> mensWears;
public String imageUrlFromServer = "http:/10.0.2.2:5757/api/public/images/";
public PhoneAdapter(Context context, List<MensWear> mensWears) {
this.context = context;
this.mensWears = mensWears;
}
#Override
public int getCount() {
return mensWears.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i,View view,ViewGroup viewGroup) {
final MensWear mensWear = mensWears.get(i);
if (view == null) {
final LayoutInflater layoutInflater = LayoutInflater.from(context);
view = layoutInflater.inflate(R.layout.phone_list, null);
}
//For text
TextView prdId = view.findViewById(R.id.mensWearIdForHompePage);
prdId.setText(prdId.toString());
//For images
final ImageView imageView = view.findViewById(R.id.phoneImages);
if(!TextUtils.isEmpty(mensWear.getFirst_wear())){
Picasso.with(context).load(imageUrlFromServer+mensWear.getFirst_wear())
.into(imageView);
}
return view;
}
}
My Class extending Fragment
public class Phones extends Fragment {
private GridView gridView;
private List<MensWear> mensWears;
private PhoneAdapter adapter;
public Phones() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_phones,container,false);
}
#Override
public void onViewCreated(#NonNull View view,#Nullable Bundle savedInstanceState) {
super.onViewCreated(view,savedInstanceState);
gridView = view.findViewById(R.id.gridHolder);
gridView = view.findViewById(R.id.gridHolder);
Call<MensWearResponse> wearResponseCall =
Service.getInstance().getApi().getAllMensWears();
wearResponseCall.enqueue(new Callback<MensWearResponse>() {
#Override
public void onResponse(Call<MensWearResponse> call,Response<MensWearResponse> response) {
mensWears = response.body().getMensWears();
for (MensWear mwr : mensWears){
Log.d("Name", mwr.getFirst_wear());
}
adapter = new PhoneAdapter(getActivity(), mensWears);
gridView.setAdapter(adapter);
}
#Override
public void onFailure(Call<MensWearResponse> call,Throwable t) {
}
});
}
}
My Layout Files
The Grid Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context="com.nelbuc.nelbuc.goodWears"
>
<Grid
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:columnWidth="100dp"
android:numColumns="2"
android:verticalSpacing="24dp"
android:horizontalSpacing="10dp"
android:stretchMode="spacingWidthUniform"
android:id="#+id/gridHolder"
>
</Grid>
</RelativeLayout>
The List Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/phoneList"
android:layout_width="190dp"
android:background="#fff"
android:layout_height="180dp"
>
<TextView
android:id="#+id/mensWearIdForHompePage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Apple"
android:textStyle="normal|italic"
android:textSize="25dp" />
<ImageView
android:id="#+id/phoneImages"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
/>
</RelativeLayout>
</RelativeLayout>
Error message clearly says that GridView is null. There is no GridView in your layout, there is only Grid. Change Grid to GridView.
In your layout, You are using only Grid. Change from Grid to GridView
Create ArrayList and add the model i.e MensWear into that list like this following and then pass this list into your adpater:
ArrayList<MensWear > arrayList_mens = new ArrayList<MensWear>();
for (MensWear mwr : mensWears)
{
Log.d("Name", mwr.getFirst_wear());
arrayList_mens.add(mwr);
}
I'm trying to show an additional CardView that contains a different layout but have got lost with my code. I'm also unsure of how to to show the array of strings within a GridView for the CardView itself. Does anyone know where I may have gone wrong & what can be done so that the following can be achieved?:
Place the CardView containing the GridView wherever I want within the RecyclerView.
Show the array of strings in a GridView within a CardView
What I want to add to the RecyclerView (above the Item A CardView)
RecyclerView current contents
Fragment class
public class MyFragment extends android.support.v4.app.Fragment {
private MonRecyclerAdapterWithGrid adapterG;
static final String[] frenchVowels = new String[]{
"a", "e", "i", "o", "u", "y"
};
public MyFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_rv, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
View v = getView();
assert v != null;
recyclerView = v.findViewById(R.id.my_recyclerview);
linearLayoutManager = new LinearLayoutManager(getActivity());
MyRecyclerAdapter adapter = new MyRecyclerAdapter(getContext(), getHeader(), getListItemsG(), getListItemsT());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
super.onActivityCreated(savedInstanceState);
}
RecyclerView recyclerView;
LinearLayoutManager linearLayoutManager;
public RecyclerViewHeader getHeader()
{
return new RecyclerViewHeader();
}
public List<RecyclerViewItemGV> getListItemsG() {
List<RecyclerViewItemGV> rvItemsG = new ArrayList<>();
RecyclerViewItemGV itemG = new RecyclerViewItemGV();
itemG.setTitleGV("Item A");
itemG.setVowelsGV(adapterG);
for (String fVowels : frenchVowels) {
// ?????? Still not working :-(
adapterG.addAdapterItem(new MyFragment.AdapterItem(frenchVowels));
}
rvItemsG.add(itemG);
return rvItemsG;
}
public List<RecyclerViewItemTV> getListItemsT()
{
List<RecyclerViewItemTV> rvItemsT = new ArrayList<>();
RecyclerViewItemTV itemA = new RecyclerViewItemTV();
itemA.setTitleTV("Item A");
itemA.setDescriptionTV("Feature A1");
rvItemsT.add(itemA);
RecyclerViewItemTV itemB = new RecyclerViewItemTV();
itemB.setTitleTV("Item B");
itemB.setDescriptionTV("Feature B1\nFeature B2");
rvItemsT.add(itemB);
RecyclerViewItemTV itemC = new RecyclerViewItemTV();
itemC.setTitleTV("Item C");
itemC.setDescriptionTV("Feature C1\nFeature C2\nFeature C3");
rvItemsT.add(itemC);
return rvItemsT;
}
}
RecyclerView adapter class
public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEMG = 1;
private static final int TYPE_ITEMT = 2;
private Context mContext;
RecyclerViewHeader header;
List<RecyclerViewItemGV> listItemsG;
List<RecyclerViewItemTV> listItemsT;
ValueAnimator mAnimator;
public MyRecyclerAdapter(Context context, RecyclerViewHeader header, List<RecyclerViewItemGV> listItemsG, List<RecyclerViewItemTV> listItemsT)
{
this.mContext = context;
this.header = header;
this.listItemsG = listItemsG;
this.listItemsT = listItemsT;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == TYPE_HEADER)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_header_expandcollapsebuttons, parent, false);
return new MyRecyclerAdapter.VHHeader(v);
}
else if(viewType == TYPE_ITEMG)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_gv, parent, false);
return new MyRecyclerAdapter.VHItemG(v);
}
else if(viewType == TYPE_ITEMT)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_tv, parent, false);
return new MyRecyclerAdapter.VHItemT(v);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
}
private RecyclerViewItemGV getItemG(int position)
{
return listItemsG.get(position);
}
private RecyclerViewItemTV getItemT(int position)
{
return listItemsT.get(position);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Typeface iconFont = FontManager.getTypeface(mContext, FontManager.FONTAWESOME);
if (holder instanceof MyRecyclerAdapter.VHHeader)
{
final MyRecyclerAdapter.VHHeader vhHeader = (MyRecyclerAdapter.VHHeader)holder;
}
else if (holder instanceof MyRecyclerAdapter.VHItemG){
RecyclerViewItemGV currentItemG = getItemG(position-1);
final MonRecyclerAdapterWithGrid.VHItemG vhItemG = (MyRecyclerAdapter.VHItemG)holder;
vhItemG.txtAG.setText(currentItemG.getTitleGV());
vhItemG.mGridViewG.setVisibility(View.GONE);
vhItemG.txtExpandCollapseG.setText(R.string.fa_icon_chevron_down);
vhItemG.txtExpandCollapseG.setTypeface(iconFont);
//Add onPreDrawListener
vhItemG.mGridViewG.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vhItemG.mGridViewG.getViewTreeObserver().removeOnPreDrawListener(this);
vhItemG.mGridViewG.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
vhItemG.mGridViewG.measure(widthSpec, heightSpec);
vhItemG.mGridViewHeight = vhItemG.mGridViewG.getMeasuredHeight();
return true;
}
});
vhItemG.mCardViewG.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(vhItemG.mGridViewG.getVisibility() == View.GONE){
vhItemG.expandG();
} else {
vhItemG.collapseG();
}
}
});
}
else if (holder instanceof MyRecyclerAdapter.VHItemT)
{
RecyclerViewItemTV currentItem = getItemT(position-2);
final MyRecyclerAdapter.VHItemT vhItemT = (MyRecyclerAdapter.VHItemT)holder;
vhItemT.txtA.setText(currentItem.getTitleTV());
vhItemT.txtB.setText(currentItem.getDescriptionTV());
vhItemT.txtB.setVisibility(View.GONE);
vhItemT.txtExpandCollapse.setText(R.string.fa_icon_chevron_down);
vhItemT.txtExpandCollapse.setTypeface(iconFont);
//Add onPreDrawListener
vhItemT.txtB.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
vhItemT.txtB.getViewTreeObserver().removeOnPreDrawListener(this);
vhItemT.txtB.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
vhItemT.txtB.measure(widthSpec, heightSpec);
vhItemT.textBHeight = vhItemT.txtB.getMeasuredHeight();
return true;
}
});
vhItemT.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(vhItemT.txtB.getVisibility() == View.GONE){
vhItemT.expandT();
} else {
vhItemT.collapseT();
}
}
});
}
}
// need to override this method
#Override
public int getItemViewType(int position) {
if(isPositionHeader(position))
return TYPE_HEADER;
return TYPE_ITEMG;
return TYPE_ITEMT;
}
private boolean isPositionHeader(int position)
{
return position == 0;
}
#Override
public int getItemCount() {
return listItemsG.size()+1;
return listItemsT.size()+1;
}
class VHHeader extends RecyclerView.ViewHolder{
Button btnCollapseAll, btnExpandAll;
public VHHeader(View headerView) {
super(headerView);
this.btnCollapseAll = headerView.findViewById(R.id.btn_collapseall);
this.btnExpandAll = headerView.findViewById(R.id.btn_expandall);
}
}
public class VHItemG extends RecyclerView.ViewHolder{
CardView mCardViewG;
LinearLayout mLinearLayoutG;
RelativeLayout mRelativeLayoutG;
RecyclerView mRecyclerViewG;
GridView mGridViewG;
TextView txtExpandCollapseG, txtAG;
public int mGridViewHeight;
public VHItemG(View itemView) {
super(itemView);
this.mCardViewG = itemView.findViewById(R.id.cv_gv);
this.mLinearLayoutG = itemView.findViewById(R.id.linearlayout_gv_titlerow);
this.mRelativeLayoutG = itemView.findViewById(R.id.relativelayout_gv);
this.mRecyclerViewG = itemView.findViewById(R.id.my_recyclerview);
this.txtAG = itemView.findViewById(R.id.tv_gv_A);
this.txtExpandCollapseG = itemView.findViewById(R.id.tv_gv_expandcollapse);
this.mGridViewG = itemView.findViewById(R.id.gv_a);
}
private void expandG() {
// change visibility to 'VISIBLE'
mGridViewG.setVisibility(View.VISIBLE);
// change direction of chevron to 'up'
txtExpandCollapseG.setText(R.string.fa_icon_chevron_up);
// apply animation to the height of 'txtB'
mAnimator = slideAnimator(0, mGridViewHeight);
// start the animation
mAnimator.start();
}
private void collapseG() {
// change direction of chevron to 'down'
txtExpandCollapseG.setText(R.string.fa_icon_chevron_down);
int finalHeight = mGridViewG.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
// Height will be 0, but set visibility to 'GONE'
mGridViewG.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
public ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// update height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mGridViewG.getLayoutParams();
layoutParams.height = value;
mGridViewG.setLayoutParams(layoutParams);
}
});
return animator;
}
}
public class VHItemT extends RecyclerView.ViewHolder{
CardView cardView;
LinearLayout mLinearLayout;
RecyclerView mRecyclerView;
RelativeLayout mRelativeLayout;
TextView txtExpandCollapse, txtA, txtB;
public int textBHeight;
public VHItemT(View itemView) {
super(itemView);
this.cardView = itemView.findViewById(R.id.linearlayout_tv_main);
this.mLinearLayout = itemView.findViewById(R.id.linearlayout_tv_titlerow);
this.mRelativeLayout = itemView.findViewById(R.id.relativelayout_tv);
this.mRecyclerView = itemView.findViewById(R.id.my_recyclerview);
this.txtExpandCollapse = itemView.findViewById(R.id.tv_tv_expandcollapse);
this.txtA = itemView.findViewById(R.id.tv_tv_A);
this.txtB = itemView.findViewById(R.id.tv_tv_B);
}
private void expandT() {
// change visibility to 'VISIBLE'
txtB.setVisibility(View.VISIBLE);
// change direction of chevron to 'up'
txtExpandCollapse.setText(R.string.fa_icon_chevron_up);
// apply animation to the height of 'txtB'
mAnimator = slideAnimator(0, textBHeight);
// start the animation
mAnimator.start();
}
private void collapseT() {
// change direction of chevron to 'down'
txtExpandCollapse.setText(R.string.fa_icon_chevron_down);
int finalHeight = txtB.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
// Height will be 0, but set visibility to 'GONE'
txtB.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
public ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// update height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = txtB.getLayoutParams();
layoutParams.height = value;
txtB.setLayoutParams(layoutParams);
}
});
return animator;
}
}
}
GridView adapter (currently excluded from project)
private class MyGVAdapter extends ArrayAdapter<AdapterItem> {
private List<AdapterItem> items = new ArrayList<>();
MyGVAdapter(Context context, int textviewid) {
super(context, textviewid);
}
void addAdapterItem(MyGVFragment.AdapterItem item) {
items.add(item);
}
#Override
public int getCount() {
return items.size();
}
#Override
public MyGVFragment.AdapterItem getItem(int position) {
return ((null != items) ? items.get(position) : null);
}
#Override
public long getItemId(int position) {
return position;
}
#NonNull
#Override
public View getView(final int position, View convertView, #NonNull final ViewGroup parent) {
View rowView;
if (convertView == null) {
rowView = getActivity().getLayoutInflater().inflate(R.layout.gridview_item, parent, false);
} else {
rowView = convertView;
}
TextView tv = rowView.findViewById(R.id.item_gridview);
tv.setText(items.get(position).first);
return rowView;
}
}
class AdapterItem {
String first;
AdapterItem(String first) {
this.first = first;
}
}
}
gridview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/item_gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="0dp"
android:paddingEnd="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary"
/>
</LinearLayout>
CardView with GridView (recyclerview_item_gv)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:id="#+id/cv_gv"
android:layout_marginBottom="20dp"
>
<LinearLayout
android:id="#+id/lineralayout_gv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:animateLayoutChanges="true">
<LinearLayout
android:id="#+id/linearlayout_gv_titlerow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="2dp"
android:weightSum="100">
<TextView
android:id="#+id/tv_gv_A"
android:layout_weight="90"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Medium" />
<TextView
android:id="#+id/tv_gv_expandcollapse"
android:importantForAccessibility="no"
android:clickable="true"
android:focusable="true"
android:layout_weight="10"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Large" />
</LinearLayout>
<RelativeLayout
android:id="#+id/relativelayout_gv"
android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<GridView
android:id="#+id/gv_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:layout_marginBottom="20dp"
android:stretchMode="columnWidth" />
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
CardView with TextView (recyclerview_item_tv.xml)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:id="#+id/cv_tv"
android:layout_marginBottom="20dp">
<LinearLayout
android:id="#+id/linearlayout_gv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:animateLayoutChanges="true">
<LinearLayout
android:id="#+id/linearlayout_tv_titlerow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="2dp"
android:weightSum="100">
<TextView
android:id="#+id/tv_tv_A"
android:layout_weight="90"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Medium" />
<TextView
android:id="#+id/tv_tv_expandcollapse"
android:importantForAccessibility="no"
android:clickable="true"
android:focusable="true"
android:layout_weight="10"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Large" />
</LinearLayout>
<RelativeLayout
android:id="#+id/relativelayout_tv"
android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Large" />
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
Ok so I made a quick example of how to do it. This is how the Activity class I'm posting looks like, all items are in the same RecyclerView:
Bear in mind, it might not look like your code because I am trying to use (At least for me) best practices, and also shorten the amount of code and classes by containing a lot of things in the same class.
Here is the Activity:
public class RecyclerActivity extends AppCompatActivity {
RecyclerView recycler;
ArrayList<String> data;
RecyclerView.Adapter<ViewHolder> adapter;
private static final int ITEM_TYPE = 100;
private static final int HEADER_TYPE = 101;
private static final int HEADER_TYPE_2 = 102;
private static final int GRID_TYPE = 103;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
// find recycler,
recycler = findViewById(R.id.recycler);
// set the layout
recycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
// init data,
data = new ArrayList<>();
data.add("Item A");
data.add("Item B");
data.add("Item C");
// create the adapter
adapter = createAdapter();
// set the adapter
recycler.setAdapter(adapter);
}
// creates the adapter,
private RecyclerView.Adapter<ViewHolder> createAdapter() {
return new RecyclerView.Adapter<ViewHolder>() {
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int type) {
switch (type) {
case HEADER_TYPE:
// inflate the layout,
ViewHolder holderHeader1 = new ViewHolder(inflateHelper(R.layout.header, parent));
// set an on click to the view here to create only one object,
holderHeader1.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something
}
});
return holderHeader1;
case HEADER_TYPE_2:
// inflate the layout,
ViewHolder holderHeader2 = new ViewHolder(inflateHelper(R.layout.header, parent));
// set an on click to the view here to create only one object,
holderHeader2.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something
}
});
return holderHeader2;
case ITEM_TYPE:
// inflate the layout,
ViewHolder holderItem = new ViewHolder(inflateHelper(R.layout.item, parent));
// set an on click to the view here to create only one object,
holderItem.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something
}
});
return holderItem;
case GRID_TYPE:
// inflate the layout,
ViewHolder holderGrid = new ViewHolder(inflateHelper(R.layout.grid, parent));
// set an on click to the view here to create only one object,
holderGrid.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something
}
});
return holderGrid;
default:
// inflate the layout,
ViewHolder holderItemDefault = new ViewHolder(inflateHelper(R.layout.item, parent));
// set an on click to the view here to create only one object,
holderItemDefault.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something
}
});
return holderItemDefault;
}
}
/**
* Keep the viewholder simple and the all the view finding here. This way you
* only have one viewholder.
*/
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
// go through the positions
switch (getItemViewType(position)) {
case HEADER_TYPE:
Button expandButton = viewHolder.itemView.findViewById(R.id.button);
expandButton.setText("Expand");
break;
case HEADER_TYPE_2:
Button collapseButton = viewHolder.itemView.findViewById(R.id.button);
collapseButton.setText("Collapse");
break;
case ITEM_TYPE:
// get the current item
String item = data.get(position - 3);
TextView title = viewHolder.itemView.findViewById(R.id.title);
title.setText(item);
break;
case GRID_TYPE:
break;
}
}
#Override
public int getItemCount() {
return data.size() + 3;
}
#Override
public int getItemViewType(int position) {
switch (position) {
case 0:
return HEADER_TYPE;
case 1:
return HEADER_TYPE_2;
case 2:
return GRID_TYPE;
default: return ITEM_TYPE;
}
}
};
}
private View inflateHelper(int resId, ViewGroup parent) {
return LayoutInflater.from(this).inflate(resId, parent, false);
}
// inner class for viewholder to use,
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(#NonNull View itemView) {
super(itemView);
}
}
}
You might notice that I have used one ViewHolder. This is a pattern I believe we should adopt because it simplifies code so much more. You can find the views you need in the onBind method and thus get away with using one for all types of views.
Also I add the on click listener in the onCreateViewHolder because it is much more efficient to set it there, and it allows for the viewholder to not be onClick specific.
As I said, you can use as many types as you want, you just need to check for it, and set it at the right position.
Here are the layout files if you are interested:
Header
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:gravity="center">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expand" />
</LinearLayout>
Item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:elevation="2dp"
android:layout_margin="16dp"
android:background="#drawable/rounded">
<TextView
android:id="#+id/title"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Item A"
android:textColor="#fff"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_chevron_right"
android:tint="#fff"/>
</LinearLayout>
Grid Layout (I cheated a bit here because I didn't see a reason to not hardcode vowels, although you might need to do it dynamically)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:padding="16dp"
android:background="#drawable/rounded"
android:backgroundTint="#fff"
android:elevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="16dp"
android:text="French Vowels"
android:textStyle="bold"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="#+id/a"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="a"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
<TextView
android:id="#+id/e"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="e"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
<TextView
android:id="#+id/i"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="i"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="#+id/o"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="o"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
<TextView
android:id="#+id/u"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="u"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
<TextView
android:id="#+id/y"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:text="y"
style="#style/Base.TextAppearance.AppCompat.Medium"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
Rounded Drawable
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#222"/>
<corners android:radius="6dp"/>
</shape>
For anyone reading, if you happen to use Kotlin, consider using my small library which eliminates this recycler view boilerplate to a simple chain of functions:
https://github.com/Pfuster12/BoilerCycle
i want to be able to do this to the code i have already I am new to programing please help.
- Add an icon the user can click (per item) to remove it
- When clicked that item on the list should be removed
-The item should be removed from storage as well (so it doesn't appear next time they load up the app)
here is my code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String Log_TAG = "ToDoApp";
private ToDoListManager listManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView todoList = (ListView) findViewById(R.id.todo_list);
listManager = new ToDoListManager(getApplicationContext());
ToDoItemAdapter adapter = new ToDoItemAdapter(
this,
listManager.getList()
);
ImageButton addButton = (ImageButton) findViewById(R.id.add_item);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onAddButtonClick();
}
});
}
#Override
protected void onPause() {
super.onPause();
listManager.saveList();
}
private void onAddButtonClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.add_item);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
builder.setPositiveButton(
R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ToDoItem item = new ToDoItem(
input.getText().toString(),
false
);
listManager.addItem(item);
}
});
builder.setNegativeButton(
R.string.cancel,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
}
private class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
private Context context;
private List<ToDoItem> items;
public ToDoItemAdapter(
Context context,
List<ToDoItem> items
) {
super(context, -1, items);
this.context = context;
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.to_do_item_layout, parent, false);
}
TextView textView = (TextView) convertView.findViewById(R.id.item);
CheckBox CheckBox = (CheckBox) convertView.findViewById(R.id.CheckBox);
textView.setText(items.get(position).getDescription());
CheckBox.setChecked(items.get(position).isComplete());
convertView.setTag(items.get(position));
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ToDoItem item = (ToDoItem) v.getTag();
item.toggleComplete();
notifyDataSetChanged();
}
});
return convertView;
}
}
}
todolistmanager.java
public class ToDoListManager {
private static final String APP_PREFERENCES = "todoapp";
private static final String TODO_ITEMS = "itemslist";
private List<ToDoItem> items;
private SharedPreferences savedData;
public ToDoListManager(Context context) {
savedData = context.getSharedPreferences (
APP_PREFERENCES,
Context.MODE_PRIVATE
);
String json = savedData.getString(TODO_ITEMS, null);
if(json == null) {
items = new ArrayList<>();
} else {
Type type = new TypeToken<List<ToDoItem>>() {}.getType();
items = new Gson().fromJson(json, type);
}
}
public List<ToDoItem> getList() {
return items;
}
public void addItem(ToDoItem item) {
items.add(item);
saveList();
}
public void saveList() {
SharedPreferences.Editor edit = savedData.edit();
edit.clear();
String json = new Gson().toJson(items);
edit.putString(TODO_ITEMS, json);
edit.apply();
}
}
todoItem.java
public class ToDoItem {
private String description;
private boolean isComplete;
public ToDoItem(String description,boolean isComplete) {
this.description = description;
this.isComplete = isComplete;
}
public String getDescription() {
return description;
}
public boolean isComplete() {
return isComplete;
}
public void toggleComplete() {
isComplete = !isComplete;
}
#Override
public String toString() {
return getDescription();
}
}
Activity_Main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/txtItem"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/hintTxtItem"
/>
<Button
android:id="#+id/btnAdd"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/lblBtnAdd"
android:layout_toRightOf="#id/txtItem"
/>
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/txtItem"
android:text="#string/txtEmpty"
android:gravity="center_horizontal"
/>
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/txtItem"
android:choiceMode="multipleChoice" >
</ListView>
<Button
android:id="#+id/btnDel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/lblBtnDel" />
to_do_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1">
<CheckBox
android:id="#+id/CheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"/>
<ListView
android:layout_weight="20"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/btnDel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/lblBtnDel" />
Step1: Create activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="#+id/txtItem"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="text" />
<Button
android:id="#+id/btnAdd"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/txtItem"
android:text="Add" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ListView
android:id="#+id/lvTodo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:choiceMode="multipleChoice" />
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:text="No data"
android:visibility="invisible" />
</RelativeLayout>
<Button
android:id="#+id/btnDel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Delete" />
</LinearLayout>
Step2: Create to todo_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="10dp"
android:orientation="horizontal"
android:weightSum="1">
<TextView
android:id="#+id/tvTodoName"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Learn Android"
android:textSize="20sp" />
<CheckBox
android:id="#+id/cbChooseTodo"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Step3: Define Object Todo
public class ToDoItem {
private String description;
private boolean isComplete;
public ToDoItem(String description, boolean isComplete) {
this.description = description;
this.isComplete = isComplete;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isComplete() {
return isComplete;
}
public void setComplete(boolean complete) {
isComplete = complete;
}
}
Step4: Create TodoItemAdapter class
public class TodoItemAdapter extends ArrayAdapter<ToDoItem> {
private ArrayList<ToDoItem> arrayListTodo;
private LayoutInflater layoutInflater;
public TodoItemAdapter(Context context, int resource, ArrayList<ToDoItem> objects) {
super(context, resource, objects);
this.arrayListTodo = objects;
this.layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null){
holder = new ViewHolder();
convertView = layoutInflater.inflate(R.layout.todo_item, parent,false);
holder.tvTodoName = (TextView)convertView.findViewById(R.id.tvTodoName);
holder.cbTodoChoose = (CheckBox)convertView.findViewById(R.id.cbChooseTodo);
convertView.setTag(holder);
}else {
holder = (ViewHolder)convertView.getTag();
}
final ToDoItem toDoItem = arrayListTodo.get(position);
holder.tvTodoName.setText(toDoItem.getDescription());
holder.cbTodoChoose.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
toDoItem.setComplete(isChecked);
}
});
holder.cbTodoChoose.setChecked(toDoItem.isComplete());
return convertView;
}
public static class ViewHolder{
public TextView tvTodoName;
public CheckBox cbTodoChoose;
}
}
Step5: Process on the MainActivity class
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ListView lvTodoItem;
private ArrayList<ToDoItem> toDoItems;
private TodoItemAdapter todoItemAdapter;
private Button btnDel;
private Button btnAdd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData(){
toDoItems = new ArrayList<>();
todoItemAdapter = new TodoItemAdapter(MainActivity.this, R.layout.todo_item, toDoItems);
lvTodoItem = (ListView)findViewById(R.id.lvTodo);
lvTodoItem.setAdapter(todoItemAdapter);
btnAdd = (Button)findViewById(R.id.btnAdd);
btnDel = (Button)findViewById(R.id.btnDel);
btnAdd.setOnClickListener(this);
btnDel.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnAdd:
addTodoItem();
break;
case R.id.btnDel:
deleteTodoItem();
break;
}
}
private void addTodoItem() {
}
private void deleteTodoItem() {
for (int i= toDoItems.size()-1; i>=0 ; i--){
ToDoItem toDoItem = toDoItems.get(i);
if (toDoItem.isComplete()){
toDoItems.remove(i);
}
}
todoItemAdapter.notifyDataSetChanged();
}
}
It is working fine. Thanks.
i wanted to have a custom listView so I did this:
Created an Activity:
public class PRS_MainList_Act extends ListActivity {
MainListAdapter mladp;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_prs__main_list_);
ArrayList<MainMenuItem> menuItems = new ArrayList<MainMenuItem>();
menuItems.add(new MainMenuItem(getResources().getString(R.string.main_list_connectivity), getResources().getString(R.string.main_list_connectivityDesc)));
this.mladp = new MainListAdapter(this, R.layout.man_list_item, R.id.textView1, menuItems);
setListAdapter(mladp);
}
}
Create a class for menu items:
public class MainMenuItem {
private String itemText;
private String itemDescription;
private String itemIMG;
private int itemWeight;
private String itemAssociatedActivity;
public MainMenuItem(String itemText, String itemDescription) {
this.itemText = itemText;
this.itemDescription = itemDescription;
}
public String getItemText() {
return itemText;
}
public void setItemText(String itemText) {
this.itemText = itemText;
}
public String getItemIMG() {
return itemIMG;
}
public void setItemIMG(String itemIMG) {
this.itemIMG = itemIMG;
}
public int getItemWeight() {
return itemWeight;
}
public void setItemWeight(int itemWeight) {
this.itemWeight = itemWeight;
}
public String getItemAssociatedActivity() {
return itemAssociatedActivity;
}
public void setItemAssociatedActivity(String itemAssociatedActivity) {
this.itemAssociatedActivity = itemAssociatedActivity;
}
public String getItemDescription() {
return itemDescription;
}
public void setItemDescription(String itemDescription) {
this.itemDescription = itemDescription;
}
}
Custom array adapter:
public class MainListAdapter extends ArrayAdapter<MainMenuItem> {
ArrayList<MainMenuItem> menuItems;
public MainListAdapter(Context context, int resource,
int textViewResourceId, ArrayList<MainMenuItem> menuItems) {
super(context, resource, textViewResourceId, menuItems);
this.menuItems = menuItems;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.man_list_item, parent);
}
MainMenuItem it = menuItems.get(position);
if (it != null) {
TextView titleTV = (TextView) view.findViewById(R.id.textView1);
TextView descriptionTV = (TextView) view.findViewById(R.id.textView2);
ImageView iconIV = (ImageView)view.findViewById(R.id.imageView1);
if (titleTV != null) {
titleTV.setText(it.getItemText());
}
if(descriptionTV != null){
descriptionTV.setText(it.getItemDescription());
}
if(iconIV != null){
if(it.getItemText().equals(getContext().getResources().getString(R.string.main_list_connectivity)))
iconIV.setImageResource(R.drawable.network_connections);
}
}
return view;
}
}
and here are my activity layout and item layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PRS_MainList_Act" >
<ListView android:id="#android:id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
Item Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/ic_launcher" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="TextView" />
</LinearLayout>
</LinearLayout>
I got this error saying: java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
Thanks in advance for your help.
You can't use this version of the inflate method:
view = vi.inflate(R.layout.man_list_item, parent);
because this will add the inflated View to the parent, which isn't allowed in a ListView. Instead use this version:
view = vi.inflate(R.layout.man_list_item, parent, false);
which will inflate the view but will not add it to the parent. This version is important because it will provide the proper LayoutParams for your inflated view.