I'm making an app that makes use of a GridView to display subcategories.
I have the categories displayed on screen and when clicked a dialog appears with a GridView displaying subcategories and a button to view everything in that category.
Here's the problem:
Sometimes the GridView doesn't load on the first click, I have to close it and then click on the category again for it to open. Categories are basically images with a textview on top. Pictures are loaded from the Internet.
Code for Dialog:
public class dialogFragment extends android.support.v4.app.DialogFragment {
private Button mViewAll;
private GridView mSubCatsView;
public ArrayList<category> mCats = new ArrayList<>();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_fragment, container);
mCats.addAll(((shopActivity)getActivity()).mDialogCats);
mViewAll = v.findViewById(R.id.viewAllBTN);
mSubCatsView = v.findViewById(R.id.subCatsView);
final gridAdapter adapada = new gridAdapter(getActivity(), mCats);
mSubCatsView.setAdapter(adapada);
mSubCatsView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
ArrayList<category> subSubCats = new ArrayList<>();
for (int y = 0; y < ((shopActivity)getActivity()).mCategoriesAll.size(); y++){
if(mCats.get(i).getId() == ((shopActivity)getActivity()).mCategoriesAll.get(y).getParent()){
subSubCats.add(((shopActivity)getActivity()).mCategoriesAll.get(y));
}
}
if(subSubCats.size() > 0){
mCats.clear();
mCats.addAll(subSubCats);
adapada.notifyDataSetChanged();
}
}
});
mViewAll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return v;
}
}
If anyone else has this problem, I fixed it by using a RecyclerView + GridLayoutManager to mimic a GridView.
Related
I am having an issue updating the ListView in my Android application. I have searched for the solution and read multiple answers but none solved my issue:
android-listview-repeating-old-data-after-refresh
android-requestlayout-improperly-called
android-listview-not-refreshing-after-notifydatasetchanged
android-listview-getview-being-called-multiple-times-on-unobservable-views
Issue
I have a listview with 2 items displayed like this:
Item 1 (position 0)
Item 2 (position 1)
After reloading the data from the source I get the same 2 items, but in the listview it is displayed like this:
Item 2 (position 0)
Item 2 (position 1)
However, when I click on the position 0 in new list it shows correct data of Item 1 (click on position 1 it also shows correct data of Item 2).
The problem is that it displays Item 2 on position 0 and on position 1 (twice).
Here is the code where list is updated and adapter is setup:
public class FishTankFragment extends DeviceFragment {
...
private final List<FishTankStatus.Schedule> schedulesList = new ArrayList<>();
private ScheduleAdapter scheduleAdapter;
...
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
scheduleAdapter = new ScheduleAdapter(view.getContext(), schedulesList);
screenBinding.lvSchedules.setAdapter(scheduleAdapter);
screenBinding.lvSchedules.setOnItemClickListener((parent, view1, position, id) -> {
new ScheduleItemClickListener(this.getContext(), schedulesList.get(position), position);
});
...
}
#Override
public <T> void onResponse(T responseObject) {
...
schedulesList.clear();
schedulesList.addAll(data.getSchedules());
scheduleAdapter.notifyDataSetChanged();
...
}
Here is Adapter code:
public class ScheduleAdapter extends BaseAdapter {
private ScheduleItemBinding itemBinding;
private final List<FishTankStatus.Schedule> schedules;
private final Context context;
public ScheduleAdapter(#NonNull Context context, #NonNull List<FishTankStatus.Schedule> objects) {
this.context = context;
schedules = objects;
}
#Override
public int getCount() {
return schedules.size();
}
#Override
public FishTankStatus.Schedule getItem(int position) {
return schedules.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
itemBinding = ScheduleItemBinding.inflate(LayoutInflater.from(context));
view = itemBinding.getRoot();
}
if (!schedules.isEmpty()) {
String start = StringUtils.printTime(schedules.get(position).getStart());
String end = StringUtils.printTime(schedules.get(position).getEnd());
itemBinding.tvScheduleStart.setText(start);
itemBinding.tvScheduleEnd.setText(end);
FishTankStatus.Schedule schedule = schedules.get(position);
for (String device : schedule.getDevices()) {
switch (device) {
case "something":
itemBinding.ivYellowlightIcon.setVisibility(View.VISIBLE);
break;
case "something 1":
itemBinding.ivBluelightIcon.setVisibility(View.VISIBLE);
break;
case "something 2":
itemBinding.ivAirIcon.setVisibility(View.VISIBLE);
}
}
if (schedules.get(position).getActive()) {
ColorStateList white = ColorStateList.valueOf(
view.getResources().getColor(R.color.white, view.getContext().getTheme()));
itemBinding.lySchedule.setBackground(ResourcesCompat.getDrawable(view.getResources(),
R.drawable.rectangle_p_light_8,
view.getContext().getTheme()));
...
}
}
return view;
}
}
ListView has width and height set to match_parent in parent ConstraintLayout where width=0dp (has parent) and height=match_parent
See the video:
screen recording
Thank you for all the help.
I debugged the app. After clearing schedulesList.clear() it contained 0 items in Fragment and also in BaseAdapter. After addAll items from the source it contained correct items in schedulesList both in Fragment and BaseAdapter.
I tried to fill the data in Adapter as separate List object using clear and addAll.
I will answer my own question for the future visitors...
Just use RecyclerView
It solved all my issues. But I still do not know why the above problem happened.
I am using fragments in my app. Every fragment has a listview. The ListViews are custom listviews containing a single image view.
<ImageView
android:id="#+id/imageView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="#android:drawable/ic_notification_overlay" />
The listview items are images. I want to implement searchview. I want to search by name of each listview item eg "jingle bells etc" and also by number i.e "1,2. . . and so on.
My java file containing listview titles is.
public class carolFrag extends Fragment {
//code
public carolFrag() {
// Required empty public constructor
}
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
private static final String TAG = "carolFrag";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup main_content, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_carol, main_content, false);
final int[] menuImage = {R.drawable.carol_1_title, R.drawable.carol_2_title,R.drawable.carol_3_title,R.drawable.carol_4_title,R.drawable.carol_5_title,R.drawable.carol_6_title,R.drawable.carol_7_title,R.drawable.carol_8_title,R.drawable.carol_9_title,R.drawable.carol_10_title,R.drawable.carol_11_title};
final ListView listView = (ListView) view.findViewById(R.id.CarolList);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Intent intent1 = new Intent (getActivity(), PackageC.class)
intent1.putExtra("position", position);
startActivity(intent1);
}
});
AdapterCarols adapter = new AdapterCarols(getContext(), menuImage);
listView.setAdapter(adapter);
// Inflate the layout for this fragment
return view;
}
}
I am unable to make any logic as the array has drawables in it.
Because the array is full of drawables, and it's not a database thing or anithing every solution you i'll get will be a work around. The simples, i believe, is to have another array maybe an - String[] - with the names of the drawables in the same order they are in the original - final int[] menuImage - you can make the search in the array of String and save the position of the results. Then use those positions to create a new array ( int[] ) putting in this new array the drawables that matches those positions. Finally change the adapter of the list view, passing the array with the results and notifydatachange(); in the listview for it to update visually.
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup
main_content, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_carol, main_content, false);
final int[] menuImage = {R.drawable.carol_1_title, R.drawable.carol_2_title,R.drawable.carol_3_title,R.drawable.carol_4_title,R.drawable.carol_5_title,R.drawable.carol_6_title,R.drawable.carol_7_title,R.drawable.carol_8_title,R.drawable.carol_9_title,R.drawable.carol_10_title,R.drawable.carol_11_title};
final ListView listView = (ListView) view.findViewById(R.id.CarolList);
SearchView sv = view.findviewById(R.id.searchview);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
public boolean onQueryTextChange(String par1)
{
return false;
}
public boolean onQueryTextSubmit(String par1)
{
int [] searchresults = PerformSearch(par1);
AdapterCarols newadapter = new
AdapterCarols(getContext(), searchresults);
listView.setAdapter(adapter);
listview.invalidate(); // don't remember listview refresh method. I work with Recyclerview, they have a notifyDatasetChange(); method.
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Intent intent1 = new Intent (getActivity(), PackageC.class)
intent1.putExtra("position", position);
startActivity(intent1);
}
});
AdapterCarols adapter = new AdapterCarols(getContext(), menuImage);
listView.setAdapter(adapter);
// Inflate the layout for this fragment
return view;
}
private int[] PerformSearch(par1)
{
String [] strcarols = {carol_1_title,carol_2_title,carol_3_title,carol_4_title,carol_5_title,carol_6_title,carol_7_title,carol_8_title,carol_9_title,carol_10_title,carol_11_title};
int[] menuImage = {R.drawable.carol_1_title, R.drawable.carol_2_title,R.drawable.carol_3_title,R.drawable.carol_4_title,R.drawable.carol_5_title,R.drawable.carol_6_title,R.drawable.carol_7_title,R.drawable.carol_8_title,R.drawable.carol_9_title,R.drawable.carol_10_title,R.drawable.carol_11_title};
int[] results = new int[];
int carolsresultcount = 0, index =0;
/// simplest way
for(String carol:strcarols)
{
if(carol.contains(par1))
{
results [carolsresultcount++] = menuImage [index];
}
index++;
}
return results;
}
I hope this can solve your problem.
I am creating an app similar to flipkart. I have viewpager with images and I have horizontal scroll gridview to load products like new products, favourite products, best products so on.
Everything is loading fine accept that strange issue when I open the app the app automatically shows from the middle.
How do I force it to show the screen from top rather than middle.
For Slideshow I am using viewpager and for horizontal scrollview I am using TwoWayGridView API.
Has anybody come across this issue? How do I force the app to run from the top?
Please check the screenshot below:
The above screen shows the screen loads in the middle and not from top.
PS: This is from flipkart app. Showing how it would show on my app? Sorry not allowed to share the app's design part.
#SuppressWarnings({"unchecked" })
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if (rootView != null)
{
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null)
parent.removeView(rootView);
}
try
{
rootView = inflater.inflate(R.layout.main, container, false);
}
catch (InflateException e)
{
}
TextView[] bestproduct = new TextView[]
{
(TextView) rootView.findViewById(R.id.bestproduct1),
(TextView) rootView.findViewById(R.id.bestproduct2),
};
RelativeLayout [] relativeLayout = new RelativeLayout[]
{
(RelativeLayout) rootView.findViewById(R.id.relativeLayout1),
(RelativeLayout) rootView.findViewById(R.id.relativeLayout2),
};
bannerItems = new ArrayList<String>();
newproductList = new ArrayList<ProductFrontScreenDetails>();
dbmaster = new dbMaster(getActivity());
customerID = dbmaster.getCustID();
final ScrollView main = (ScrollView) rootView.findViewById(R.id.scrollView1);
main.scrollTo(0,0);
progressContainer = rootView.findViewById(R.id.progressContainer);
progressContainer.setVisibility(View.INVISIBLE);
viewPager = (ViewPager)rootView.findViewById(R.id.myviewpager);
myPagerAdapter = new MyPagerAdapter();
viewPager.setAdapter(myPagerAdapter);
mIndicator = (CirclePageIndicator)rootView.findViewById(R.id.indicator);
mIndicator.setViewPager(viewPager);
TAG_SUCCESS = getResources().getString(R.string.tagsuccess);
TAG_DETAIL = getResources().getString(R.string.tagdetails);
TAG_IMAGE = getResources().getString(R.string.productimage);
TAG_NAME = getResources().getString(R.string.productname);
TAG_BANNER_IMAGE = getResources().getString(R.string.bannerimage);
TAG_PRICE = getResources().getString(R.string.productprice);
TAG_DISCOUNT = getResources().getString(R.string.productdiscount);
FetchBannerImagesData();
gridViewnew = (TwoWayGridView) rootView.findViewById(R.id.newproductgridview);
gridViewnew.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(TwoWayAdapterView<?> parent, View view, int position, long id)
{
}
});
gridView1 = (TwoWayGridView) rootView.findViewById(R.id.gridView1);
gridView1.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(TwoWayAdapterView<?> parent, View view, int position, long id)
{
}
});
gridView2 = (TwoWayGridView) rootView.findViewById(R.id.gridView2);
gridView2.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(TwoWayAdapterView<?> parent, View view, int position, long id)
{
}
});
return rootView;
}
I have a listview with several items. When clicking on an item, an Activity is opened. However, when I click fast several times on the item, the activity, asociated with it, is opened several times. How to open the item only once?
I use the following code:
private OnItemClickListener newsfeedClickHandler = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MyObject newsfeed = adapter.getItem(position);
onNewsfeedClick(newsfeed);
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_newsfeed, container, false);
...
listView = (ListView) view.findViewById(R.id.newsfeeds);
listView.setOnItemClickListener(newsfeedClickHandler);
listView.setAdapter(adapter);
...
return view;
}
private void onNewsfeedClick(MyObject newsfeed) {
Intent intent = createIntent(newsfeed);
startActivity(intent);
}
The correct way to prevent calls to the ListView items would be to (obviously) disable the OnItemClickListener:
private void onNewsfeedClick(MyObject newsfeed) {
listView.setOnItemClickListener(null);
Intent intent = createIntent(newsfeed);
startActivity(intent);
}
Re-set the listener at onResume, when this activity is visible again.
#Override
protected void onResume() {
super.onResume();
listView.setOnItemClickListener(newsfeedClickHandler);
}
Maintain a boolean value say isItemClicked and reset it when you return back to the listview.
private boolean isItemClicked;
private OnItemClickListener newsfeedClickHandler = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (!isItemClicked) {
isItemClicked = true;
MyObject newsfeed = adapter.getItem(position);
onNewsfeedClick(newsfeed);
}
}
};
private void resetIsItemClicked() {
isItemClicked = false;
}
To prevent multiple clicks on ListView Items, add the following code in your listview click listener:
if (SystemClock.elapsedRealtime() - mLastClickTimeListViewItem < 1000){
return;
}
In my fragment, I have 4 ListViews (all 4 containing custom rows with a radio button) where a user needs to select a row for each ListView. Initially I was having trouble with getting the radio button to be checked whenever the user selects a particular row, however I came across this solution which worked well for me https://stackoverflow.com/a/12823457/3739918
Now everything is good, except I'm unable to retain the checked radio buttons after a configuration change (eg. phone changes from portrait to landscape or vice versa). I have tried to using setRetainInstance(true) which works to retain the selections prior to the configuration change (I just use an integer array to keep track of the user selections in the different list views), however I have been unsuccessful in using this information to recheck the corresponding radio button after the configuration change.
Here is the code of my fragment containing the ListViews (minus irrelevant lines):
public class FourBandFrag extends Fragment implements
AdapterView.OnItemClickListener {
private ArrayList<ListView> lists = new ArrayList<ListView>();
private ArrayList<CustomAdapter> adapters = new ArrayList<CustomAdapter>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
View result = inflater.inflate(R.layout.fourbandlayoutfrag, container,
false);
return result;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lists.add((ListView) getActivity().findViewById(R.id.FourListView1));
lists.add((ListView) getActivity().findViewById(R.id.FourListView2));
lists.add((ListView) getActivity().findViewById(R.id.FourListView3));
lists.add((ListView) getActivity().findViewById(R.id.FourListView4));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(2)));
adapters.add(new CustomAdapter(getActivity(), generateData(3)));
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
for (int q = 0; q < lists.size(); q++) {
lists.get(q).setOnItemClickListener(this);
}
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//This checks the corresponding radio button for the corresponding listview
((CustomAdapter) parent.getAdapter()).setSelectedIndex(position);
((CustomAdapter) parent.getAdapter()).notifyDataSetChanged();
}
}
The CustomAdapter.java looks like (minus irrelevant lines):
public class CustomAdapter extends ArrayAdapter<Model> {
private final Context context;
private final ArrayList<Model> modelsArrayList;
private int selectedIndex = -1;
public CustomAdapter(Context context, ArrayList<Model> modelsArrayList) {
super(context, R.layout.listitem, modelsArrayList);
this.context = context;
this.modelsArrayList = modelsArrayList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.listitem, parent, false);
RadioButton radiobutton = (RadioButton) rowView
.findViewById(R.id.radioButton);
// Check the correct radio button when person selects a listview item
if (selectedIndex == position) {
radiobutton.setChecked(true);
} else {
radiobutton.setChecked(false);
}
return rowView;
}
public void setSelectedIndex(int index) {
selectedIndex = index;
}
}
Anyone have ideas?
Thank you
Update 1
Because a radio button is only checked when the user clicks on a row, I decided to simulate a click using the information retained regarding the user selections prior to the configuration change. So now my fragment looks like this:
public class FourBandFrag extends Fragment implements
AdapterView.OnItemClickListener {
private ArrayList<ListView> lists = new ArrayList<ListView>();
private ArrayList<CustomAdapter> adapters = new ArrayList<CustomAdapter>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
View result = inflater.inflate(R.layout.fourbandlayoutfrag, container,
false);
return result;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lists.add((ListView) getActivity().findViewById(R.id.FourListView1));
lists.add((ListView) getActivity().findViewById(R.id.FourListView2));
lists.add((ListView) getActivity().findViewById(R.id.FourListView3));
lists.add((ListView) getActivity().findViewById(R.id.FourListView4));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(2)));
adapters.add(new CustomAdapter(getActivity(), generateData(3)));
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
for (int q = 0; q < lists.size(); q++) {
lists.get(q).setOnItemClickListener(this);
}
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
// Retain radio button selections after configuration change
for (int w = 0; w < bandRowNumber.length; w++) {
if (bandRowNumber[w] != unselected) {
lists.get(w).performItemClick(
lists.get(w).getAdapter()
.getView(bandRowNumber[w], null, null),
bandRowNumber[w],
lists.get(w).getAdapter().getItemId(bandRowNumber[w]));
Log.d(TAG, "Rechecking radio button " + bandRowNumber[w] + " from ListView " + w);
}
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//This checks the corresponding radio button for the corresponding listview
((CustomAdapter) parent.getAdapter()).setSelectedIndex(position);
((CustomAdapter) parent.getAdapter()).notifyDataSetChanged();
}
}
This certainly does attempt to recheck the correct radiobuttons judging from the logcat I'm getting, however the radiobuttons remain unchecked after the config change. Here is what it looks like:
In portrait mode I make a selection in each of the listviews.
http://s17.postimg.org/nm4wyve4v/portrait.png
I change the phone to landscape mode and the radio button selections dissapear.
http://s10.postimg.org/459rrgc9l/landscape.png
The logcat after changing from portrait to landscape is:
07-02 12:56:14.407: D/FourBandFrag(30090): Rechecking radio button 0 from ListView 0
07-02 12:56:14.417: D/FourBandFrag(30090): Rechecking radio button 1 from ListView 1
07-02 12:56:14.427: D/FourBandFrag(30090): Rechecking radio button 2 from ListView 2
07-02 12:56:14.427: D/FourBandFrag(30090): Rechecking radio button 3 from ListView 3
Any suggestions for a fix?
This used as per your condition
View rowView = null;
if (convertView == null) {
View rowView = inflater.inflate(R.layout.listitem, parent, false);;
} else {
rowView = convertView;
}