Android button onClick intercepts scroll - android

I have a Fragment which consists of a Button overlaid on a FrameLayout. A second ListView Fragment is inserted into the FrameLayout. The ListView scrolls correctly except if the touch event starts on top of the Button. The Button's onClick listener seems to intercept the scroll of the beneath ListView. How can I have the Button process click events, but not scroll events.
I have a basic solution working using a GestureDetector on the Button and passing the onScroll event to the ListView's smoothScrollBy function. This doesn't work easily for fling events though.
This question seems similar albeit the reverse situation. I don't think the accepted answer helps me.
Example:
main_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/sub_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="#+id/button"
android:layout_width="80dp"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#999"
android:text="Button" />
</RelativeLayout>
Inflated by MainFragment:
public class MainFragment extends Fragment {
private static final String TAG = MainFragment.class.getSimpleName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_fragment, container, false);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "click");
}
});
FragmentTransaction fragmentTransaction = getActivity()
.getSupportFragmentManager().beginTransaction();
ListFragment f = new ListFragment();
fragmentTransaction.replace(R.id.sub_content, f);
fragmentTransaction.commit();
return view;
}
}
The Button has an onClickListener and a second fragment is inflated in place of the FrameLayout:
fragment_item_list.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Inflated by ListFragment:
public class ListFragment extends Fragment {
private static final String TAG = ListFragment.class.getSimpleName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_item_list,
container, false);
ListView listView = (ListView) view.findViewById(R.id.list);
List<String> list = new ArrayList<String>();
for (int i=0; i<30; i++) {
list.add("Item: " + i);
}
MyAdapter adapter = new MyAdapter(getActivity(), list);
listView.setAdapter(adapter);
return view;
}
private class MyAdapter extends BaseAdapter {
private List<String> items;
private Context context;
public MyAdapter(Context context, List<String> items) {
this.items = items;
this.context = context;
}
#Override
public int getCount() {
return items.size();
}
#Override
public String getItem(int i) {
return items.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View convertView, ViewGroup parent) {
if (convertView==null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.list_item, parent, false);
}
TextView textView = (TextView) convertView.findViewById(
R.id.list_item_text);
textView.setText(getItem(i));
return convertView;
}
}
}

The solution I found was to remove the onClickListener on the button and instead have a SimpleGestureDetector on the Button (see the docs).
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapUp(MotionEvent event) {
clickButton();
return true;
}
}
Where the button implements this in an onTouchListener:
mDetector = new GestureDetectorCompat(getActivity(), new MyGestureListener());
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return mDetector.onTouchEvent(motionEvent)
|| dispatchTouchEvent(motionEvent);
}
});
And the Button passes the touch event to the ListView via an interface (inside dispatchTouchEvent function) and calls:
listView.dispatchTouchEvent(motionEvent)
Useful reading includes this SO question and also this.

Related

Change Fragment on setOnItemClickListener to ListView with CardView

I have a ListView that uses a CardView to inflate it's layout. When the user clicks on the the first item in the ListView, this should change the Fragment. However, I am unsure of how to do this. I attempted to change the Fragment in the adapter class (CustomAdapter.java) and it didn't work. I also have tried doing this in the Fragment the ListView is in but it didn't work either (the app didn't crash when I clicked one of the items - nothing happened):
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new DesignsWorkshopFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
}
});
SuppliersFragment.java:
public class SuppliersFragment extends Fragment {
CustomAdapter adapter;
ListView lv;
public SuppliersFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_suppliers, container, false);
lv = view.findViewById(R.id.lvFragmentSuppliers);
adapter = new CustomAdapter(getContext(), getData());
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new DesignsWorkshopFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
}
});
return view;
}
private ArrayList getData() {
ArrayList<SuppliersCardview> suppliersCardview = new ArrayList<>();
SuppliersCardview s = new SuppliersCardview();
s.setThumbnail(R.drawable.designs_workshop_logo);
s.setName("Designs Workshop");
suppliersCardview.add(s);
s = new SuppliersCardview();
s.setThumbnail(R.drawable.organic_clothing_logo);
s.setName("Organic Clothing Industries");
suppliersCardview.add(s);
s = new SuppliersCardview();
s.setThumbnail(R.drawable.suns_sewing_ltd);
s.setName("Sun's Sewing Ltd");
suppliersCardview.add(s);
return suppliersCardview;
}}
CustomAdapter.java:
public class CustomAdapter extends BaseAdapter {
Context c;
ArrayList<SuppliersCardview> suppliersCardview;
public CustomAdapter(Context c, ArrayList<SuppliersCardview> suppliersCardview) {
this.c = c;
this.suppliersCardview = suppliersCardview;
}
#Override
public int getCount() {
return suppliersCardview.size();
}
#Override
public Object getItem(int position) {
return suppliersCardview.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(c).inflate(R.layout.cardview_layout, parent, false);
}
final SuppliersCardview s = (SuppliersCardview) this.getItem(position);
ImageView imageView = convertView.findViewById(R.id.ivSupplierLogo);
TextView textView = convertView.findViewById(R.id.tvSupplierName);
imageView.setImageResource(s.getThumbnail());
textView.setText(s.getName());
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Attempted to change fragment here in a switch statement
}
});
return convertView;
}
SuppliersCardview.java:
public class SuppliersCardview {
private String name;
private int thumbnail;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getThumbnail() {
return thumbnail;
}
public void setThumbnail(int thumbnail) {
this.thumbnail = thumbnail;
}}
SuppliersFragment XML:
<FrameLayout 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="com.miguelpeachey.marketplacesimulator.Fragments.SuppliersFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/tvBrowseSuppliersHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#bfbdbd"
android:fontFamily="#font/nunito_sans"
android:paddingBottom="5dp"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:text="Browse Suppliers"
android:textSize="25sp" />
<ListView
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:id="#+id/lvFragmentSuppliers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/colorTransparent"
android:dividerHeight="20dip"/>
</LinearLayout>
CardView XML:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="40dp"
android:orientation="vertical"
app:cardPreventCornerOverlap="false"
app:ignore="NamespaceTypo"
card_view:cardBackgroundColor="#cccbcb"
card_view:cardCornerRadius="15dp"
card_view:cardElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/ivSupplierLogo"
android:layout_width="150dp"
android:layout_height="120dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:src="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/tvSupplierName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ivSupplierLogo"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:fontFamily="#font/brawler"
android:text="Supplier"
android:textColor="#232323"
android:textSize="22sp" />
</RelativeLayout>
So how can I replace/change fragments on the ListView's item click that uses a CardView as its layout? Other people's solutions did not help me.
I have used this website as a tutorial to create the CardView and inflate the ListView's layout (some code here is from the website).
You have your object of fragment now you need to use fragment manager and replace existing fragment with fragment you want to show.
DesignsWorkshopFragment fragment2=new DesignsWorkshopFragment();
FragmentManager fragmentManager=getActivity().getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_main,fragment2,"tag");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Only creating your fragment's instance will not show it in activity.
Adding and replacing of fragment is done inside activity.You need to notify your activity on the click of item view in your ListView.This can be done using interfaces.
create one interface:
public interface ClickListener{
public void onClick();
}
Implement this interface in your activity.And when you are creating the Fragment pass "this" as reference inside fragment's constructor.Like this :
fragment = new DesignsWorkshopFragment(this);
Inside fragment, you need to create the interface reference.
private ClickListener clickListener ;
Inside fragment initialize this interface reference
DesignsWorkshopFragment(ClickListener clickListener){
this.clickListener = clickListener;
}
Now do the same thing when you are creating adapter.
adapter = new CustomAdapter(getContext(), getData(),clickListener);
Inside adapter create and intialize interface reference.
private ClickListener clickListener ;
public CustomAdapter(Context c, ArrayList<SuppliersCardview> suppliersCardview,
ClickListener clickListener ) {
this.c = c;
this.suppliersCardview = suppliersCardview;
this.clickListener = clickListener;
}
and whenever a click is happening. just call the interface method.
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
clickListener.onClick();
}
});
this will give a callback inside your activity's interfcae implementation. In here
public void onClick(){
//write your code for adding or replacing fragment.
}
I managed to get this working by just removing
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
in my CustomAdapter.java class.

Listview and button inside recyclerview

I have a recyclerview which has some cards inside it. Each card has a button and a listview inside it. I want listview to appear only when button is clicked. Initially I set onClickListener for button and onTouchListener for recyclerview but it didn't work for button. It only identified recyclerview listener, not button click listener. How can I set both listeners independently? Such that recyclerview touchlistener doesn't interfere in button click listener.
Secondly, I have two adapter here- one for listview and one for recyclerview. Listview adapter is called inside recyclerview adapter. If I call listview adapter when button is clicked, context is not found which I initially passed in recyclerview adapter.
This is recyclerview adapter:
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ViewHolder>{
static Context activity;
ArrayList<ChatModel> chats = new ArrayList<ChatModel>();
boolean visible = false;
public ChatAdapter(Context a,ArrayList<ChatModel> _chats){
activity = a;
chats = _chats;
}
public static class ViewHolder extends RecyclerView.ViewHolder{
ImageButton expand;
ListView comments;
public ViewHolder(View v) {
super(v);
expand = (ImageButton)v.findViewById(R.id.chat_open);
comments = (ListView)v.findViewById(R.id.commentList);
}
}
#Override
public int getItemCount() {
// TODO Auto-generated method stub
if(chats.size()<=0)
return 0;
return chats.size();
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// TODO Auto-generated method stub
try{
holder.comments.setVisibility(View.GONE);
holder.expand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("TAG","Expand clicked");
if (visible) {
visible = false;
holder.comments.setVisibility(View.GONE);
} else {
visible = true;
CommentsAdapter adap = new CommentsAdapter(activity, chats.get(position).getCommentList());
holder.comments.setAdapter(adap);
holder.comments.setVisibility(View.VISIBLE);
}
}
});
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
// TODO Auto-generated method stub
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.chat_item_card, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
}
This is listview adapter:
public class CommentsAdapter extends ArrayAdapter<CommentModel>{
public Context context;
ArrayList<CommentModel> data;
CommentModel detail;
public CommentsAdapter(Context a, ArrayList<CommentModel> d) {
super(a, R.layout.comment_item, d);
context = a;
data=d;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
detail = data.get(position);
View vi = inflater.inflate(R.layout.comment_item, parent, false);
TextView comment = (TextView) vi.findViewById(R.id.comment);
comment.setText(detail.getComment());
return vi;
}
}
This is cardview layout (row of recyclerview):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_margin="5dp"
android:background="#e6e6e6"
card_view:cardCornerRadius="5dp"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#272626">
<ImageButton
android:layout_width="30dp"
android:layout_height="30dp"
android:background="#drawable/expand"
android:id="#+id/chat_open"
android:layout_marginRight="4dp"
android:padding="2dp"
android:clickable="true"/>
<ListView
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_below="#+id/chat_open"
android:layout_marginTop="5dp"
android:layout_alignLeft="#+id/chat_open"
android:layout_marginRight="4dp"
android:layout_marginBottom="3dp"
android:id="#+id/commentList">
</ListView>
</RelativeLayout>
</android.support.v7.widget.CardView>

setOnItemClickListener doesn't work for a button in a ListView

I am trying to place a button in each list item. This is the idea:
Text1____________[btn]
Text2____________[btn]
etc...
The XML for the items is:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:id="#+id/list_item_textview"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deleteButton"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="#null"
android:clickable="true"
android:focusable="false"
android:src="#drawable/ic_delete_black_24dp"/>
</RelativeLayout>
There are two activities sharing the same fragment. This fragment uses a SimpleCursorAdapter to fetch the data from a database. That is working perfectly.
After creating and setting the adapter, I try to find the button and do a setOnClickListener. This is NOT working.
Here is the code for the onCreateView method in the fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_scroll, container, false);
ListView listView = (ListView) rootView.findViewById(R.id.listview_item);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getActivity(),
R.layout.list_item,
((ListItems)getActivity()).getCursor(1,1),
new String[] {((ListItems) getActivity()).getColumnName()},
new int[] {R.id.list_item_textview}, 0);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(getActivity(), ((ListItems) getActivity()).getGoToClass());
intent.putExtra("apiary_id",(int) id);
intent.putExtra("hive_id", -1);
startActivity(intent);
}
});
/* SOMEWHERE BELOW IS THE PROBLEM */
View list_item_view = inflater.inflate(R.layout.list_item, container, false);
ImageButton deleteButton = (ImageButton) list_item_view.findViewById(R.id.deleteButton);
System.out.println("====================>" + deleteButton.toString()); //This prints something which includes the id of the button, so it is finding it.
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("THIS IS NOT WORKING!!!!");
}
});
return rootView;
}
This is my first android application and I'm having this problem for a few days now without any progress. Any hint is greatly appreciated!
Thank you very much!
Make a custom list adapter like this
public class CustomListAdapter extends BaseAdapter {
private String[] items;
private LayoutInflater inflater;
Context context;
public CustomListAdapter(Context c, String[] items) {
this.items = items;
inflater =LayoutInflater.from(c);
context = c;
}
#Override
public int getCount() {
return items.length;
}
#Override
public Object getItem(int location) {
return items[location];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = inflater.inflate(R.layout.list_item, null);
TextView txt = (TextView) convertView.findViewById(R.id.list_item_textview);
ImageButton button = (ImageButton) convertView.findViewById(R.id.deleteButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "clicked ",
Toast.LENGTH_SHORT).show();
}
});
txt.setText(""+items[position]);
return convertView;
}
}
and in your fragment
CustomListAdapter customListAdapter;
customListAdapter = new CustomListAdapter(getActivity(),str);
list.setAdapter(customListAdapter);
hope this will help you !!!

ListViewAnimation from nhaarman within fragment

Hi guys I have a problem with the cool lib from nhaarman
I integrated successfully his lib with an activity extends ListActivity
public class MainActivity extends ListActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setDivider(null);
MyAdapter adapter = new MyAdapter();
//setListAdapter(adapter);
ScaleInAnimationAdapter swingRightInAnimationAdapter = new ScaleInAnimationAdapter(adapter);
swingRightInAnimationAdapter.setAbsListView(getListView());
setListAdapter(swingRightInAnimationAdapter);
for(int i = 0 ; i<10; i++)
{
adapter.add("task" + String.valueOf(i));
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class MyAdapter extends ArrayAdapter<String>
{
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = (TextView) convertView;
if (tv == null) {
tv = new TextView(MainActivity.this);
}
tv.setText(getItem(position));
return tv;
}
}
}
This code above is working fine. The list_rows are fading in the screen.
But now I want to integrate this lib into a fragment with a listview within:
public class FragmentTask extends Fragment{
ListView listView;
MyAdapter adapter;
View view;
public FragmentTask() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(new Exception().getStackTrace()[0].getClassName(), new Exception().getStackTrace()[0].getMethodName());
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_tasks, container, false);
Button button = (Button) view.findViewById(R.id.btn_newTask);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.add("task");
//adapter.notifyDataSetChanged();
}
});
listView = (ListView) view.findViewById(R.id.taskListView);
listView.setDivider(null);
adapter = new MyAdapter(view.getContext());
ScaleInAnimationAdapter swingRightInAnimationAdapter = new ScaleInAnimationAdapter(adapter);
swingRightInAnimationAdapter.setAbsListView(listView);
listView.setAdapter(swingRightInAnimationAdapter);
return view;
}
private class MyAdapter extends ArrayAdapter<String>
{
Context context;
private MyAdapter(Context context) {
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_row,parent, false);
TextView title = (TextView) row.findViewById(R.id.textView);
title.setText(getItem(position));
return row;
}
}
Here is the xml fragment_tasks:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:background="#ffc7c7c7">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="New Task"
android:id="#+id/btn_newTask"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/taskListView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="#+id/btn_newTask"
/>
</RelativeLayout>
Now I have the effect that the rows only fade in if i "spam" new rows so that I have to scroll down. So the list items which were hided appear now with the fade-effect. But the other list items which have room in the listview without scrolling are not fading.
Do you understand me?
Please help me :-)
I had the same problem, but the problem is not the fragment. The height of list_view must be match_parent.
<ListView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/taskListView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="#+id/btn_newTask"
/>
description of the problem
Hope that helps

ViewPagers and PagerAdapters

I am new to Android and am trying a sample application for showing ViewPagers in a Master-Detail Flow using custom PagerAdapters and FragmentStatePagerAdapters. My application has a list of dummy items managed by a SQLiteDatabase which contain a title String, a description String, a Boolean like status, and a list of images (I plan to implement them as downloading from String urls but presently I'm just trying with a single image resource). I am having two problems in the Detail View.
My intention is to use a ViewPager with a FragmentStatePagerAdapter to show the detail view, which consists of a ViewPager with a custom PagerAdapter for showing the list of images, TextView for title and description, a ToggleButton for the like status and a delete button for deleting items from the list.
Issues:
The ViewPager with the custom PagerAdapter does not display the image. It occupies the expected space and swipes performed on it also behave as expected. Only the image is not visible.
[RESOLVED] On using the delete button, I am able to delete the item from the database, and also update the Master View accordingly, but I am not able to update the Detail View, and the app crashes.
Here is my code:
Code that calls ItemDetailActivity.java
#Override
public void onClick(View v) {
Intent detailIntent = new Intent(getContext(), ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_LIST_POSITION, holder.position);
getContext().startActivity(detailIntent);
}
ItemDetailActivity.java
public class ItemDetailActivity extends FragmentActivity {
static ItemDetailPagerAdapter idpa;
static ViewPager detailPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
idpa = new ItemDetailPagerAdapter(getSupportFragmentManager());
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
detailPager = (ViewPager) findViewById(R.id.item_detail_container);
detailPager.setAdapter(idpa);
detailPager.setCurrentItem(getIntent().getIntExtra(ItemDetailFragment.ARG_LIST_POSITION, 0));
}
}
activity_item_detail.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.trial.piclist.ItemDetailActivity"
tools:ignore="MergeRootFrame" />
ItemDetailFragment.java
public class ItemDetailFragment extends Fragment {
public static final String ARG_ITEM_ID = "item_id";
public static final String ARG_LIST_POSITION = "list_index";
public static final String ARG_TWO_PANE = "is_two_pane";
int position = -1;
long id = -1;
boolean twoPane = false;
ViewPager pager;
private PicItem mItem;
public ItemDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twoPane = getArguments().getBoolean(ARG_TWO_PANE, false);
position = getArguments().getInt(ARG_LIST_POSITION, -1);
id = getArguments().getLong(ARG_ITEM_ID, -1);
if (id == -1)
id = ItemListFragment.getIdByPosition(position);
setmItem(id);
}
public void setmItem(long id) {
if (id >= 0) {
try {
ItemListActivity.lds.open();
mItem = ItemListActivity.lds.getById(id);
ItemListActivity.lds.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (mItem != null) {
List<String> pics = new ArrayList<String>();
pics.add("1");
pics.add("2");
pics.add("3");
pics.add("4");
pics.add("5");
mItem.setPics(pics);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
DetailViewHolder holder = new DetailViewHolder();
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),
inflater, position);
pager.setAdapter(adapter);
holder.position = getArguments().getInt(ARG_LIST_POSITION);
holder.ttv = (TextView) rootView.findViewById(R.id.item_title);
holder.dtv = (TextView) rootView.findViewById(R.id.item_detail);
holder.likeButton = (ToggleButton) rootView
.findViewById(R.id.item_like);
holder.deleteButton = (Button) rootView.findViewById(R.id.item_delete);
rootView.setTag(holder);
if (mItem != null) {
holder.ttv.setText(mItem.getTitle());
holder.dtv.setText(mItem.getDescription());
holder.likeButton.setChecked(mItem.getIsLiked());
holder.likeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.toggleLike(mItem.getId());
mItem.toggleIsLiked();
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.toggleLiked(position);
}
});
holder.deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.removeItem(mItem.getId());
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.remove(position);
ItemListActivity.idpa.notifyDataSetChanged();
// What do I do so that the FragmentStatePagerAdapter is
// updated and the viewpager shows the next item.
}
});
}
return rootView;
}
static private class DetailViewHolder {
TextView ttv;
TextView dtv;
ToggleButton likeButton;
Button deleteButton;
int position;
}
}
fragment_item_detail.xml
<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"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.trial.piclist.ItemDetailFragment" >
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="200dip">
</android.support.v4.view.ViewPager>
<TableRow
android:id="#+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/item_title"
style="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello"
android:textIsSelectable="true" />
<Space
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/controls_layout" />
</TableRow>
<ScrollView
android:id="#+id/descScrollView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/item_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
</ScrollView>
</LinearLayout>
controls_layout.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:orientation="horizontal" >
<ToggleButton
android:id="#+id/item_like"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_gravity="right"
android:background="#android:drawable/btn_star"
android:gravity="center"
android:text="#string/like_list_item"
android:textOff="#string/empty_text"
android:textOn="#string/empty_text" />
<Button
android:id="#+id/item_delete"
style="?android:attr/buttonStyleSmall"
android:layout_width="30dip"
android:layout_height="30dip"
android:background="#android:drawable/ic_menu_delete"
android:text="#string/empty_text" />
</LinearLayout>
Custom PagerAdapter
ImagePagerAdapter.java
public class ImagePagerAdapter extends PagerAdapter {
LayoutInflater inflater;
List<View> layouts = new ArrayList<>(5);
// Constructors.
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (layouts.get(position) != null) {
return layouts.get(position);
}
View layout = inflater.inflate(R.layout.detail_image,
((ViewPager) container), true);
try {
ImageView loadSpace = (ImageView) layout
.findViewById(R.id.detail_image_view);
loadSpace.setBackgroundColor(0x000000);
loadSpace.setImageResource(R.drawable.light_grey_background);
loadSpace.setAdjustViewBounds(true);
} catch (Exception e) {
System.out.println(e.getMessage());
}
layout.setTag(images.get(position));
layouts.set(position, layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
#Override
public int getCount() {
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (((View) object).findViewById((view.getId())) != null);
}
}
FragmentPagerAdapter
ItemDetailPagerAdapter.java
public class ItemDetailPagerAdapter extends FragmentStatePagerAdapter {
public ItemDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putLong(ItemDetailFragment.ARG_ITEM_ID, ItemListFragment.getIdByPosition(position));
args.putInt(ItemDetailFragment.ARG_LIST_POSITION, position);
args.putBoolean(ItemDetailFragment.ARG_TWO_PANE, ItemListActivity.mTwoPane);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
openDatabase();
int c = database.getCount();
closeDatabase();
return c;
}
#Override
public int getItemPosition(Object object) {
long mId = ((ItemDetailFragment) object).getmId();
int pos = POSITION_NONE;
openDatabase();
if (database.contains(mId)) {
pos = database.getPositionById(mId);
}
closeDatabase();
return pos;
}
}
Any help is much appreciated. Thanks :)
In your ItemDetailFragment, remove the viewpager from the holder, it should be directly into the returned view, something like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),inflater, position);
pager.setAdapter(adapter);
return rootView;
}
and the ViewHolder pattern should be applied inside your PagerAdapter.
In ImagePagerAdapter.java, correct the isViewFromObject method -
#Override
public boolean isViewFromObject(View view, Object object) {
return (view == (View) object);
}
This will correct the issue of the ImageView.
In ItemDetailPagerAdapter.java, override the getItemPosition method -
#Override
public int getItemPosition(Object object) {
int ret = POSITION_NONE;
long id = ((ItemDetailFragment) object).getId();
openDatabase();
if (databaseContains(id)) {
ret = positionInDatabase(id);
}
closeDatabase();
return ret;
}
On deleting call the FragmentStatePagerAdapter.NotifyDataSetChanged() method. This will make the Adapter update itself on deleting.
Although, the FragmentStatePagerAdapter uses a list of Fragments and of stored states to implement the adapter. That is also causing trouble. To remove that, implement your own list of Fragments.

Categories

Resources