I've an activity and inside it a list fragment. In case I receive no elements for the list i'd like to add an onclick listener on the whole layout to retry the request.
Activity layout relative_browse:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/relative_browse"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
Then inside the onCreateView of the fragment i inflate fragment_list_categoriers.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_list_categories"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/gray"
android:dividerHeight="1dp"
android:listSelector="#android:color/transparent" >
</ListView>
</RelativeLayout>
I tried to add the onclick listener on the empty list inside onActivityCreated, but it doesn't work:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View view = container.findViewById(R.id.fragment_list_categories);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("DEBUG", "Click!");
}
});
}
In particular I've no "Click" log, except for a tiny border of the screen on the left (it's like if the fragment_list_categories cover all the screen except some pixels).
What's the right way to do this?
EDIT: here my onCreateView and onClick method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.inflater = inflater;
View view = inflater.inflate(R.layout.fragment_list_categories,
container, false);
this.container = (ViewGroup) view;
view.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
Log.d("DEBUG", "Click!");
}
The first thing that pops out at me is that the ListView is taking up all the space.
Since you have its height set to match_parent, it will always occupy the entire parent's space. If the list is empty, this is probably not the desired behavior.
ListViews are sometimes weird about propagating clicks through to their parent views. When you click it, it's probably just dead-ending there instead of going up the chain. That would explain why you can get the clicks on the "border"; it's just the parent view's padding.
You may want to consider changing the ListView height to wrap_content. That way if it's empty, it won't take up space and you can get your clicks.
You may also want to try to detect if it's actually empty. If you have a couple entries that don't take up the full height of the parent, what is the expected behavior if the user clicks in the "empty" area? If that should trigger the retry as well, that's fine. If not, you need to enable/disable clicking based on that.
The very first thing you should do is in the onCreateView method instantiate your RelativeLayout as
View view = inflater.inflate("Your fragment layout", null);
RelativeLayout rl = (RelativeLayout) view.findViewByID("your relative layout's ID");
rl.setOnClickListener(this);
return view;
Then implement the OnClickListener and override the onClick method as,
#override
public void onClick(View v){
Log.d("Relative LAyout", String.valueOf(v));
}
In case you have already done the above then please post your onCreateView code.
Related
For my app, I'm trying to show a list, and as soon as this list ends, the second one shall begin. The Lists are being displayed using a ListAdapter, which again is part of a fragment. Everything works very well, the lists appear correctly, but I can't figure out a way to put one list under the other. I thought this shouldn't be all too hard.
Summary:
What I have:
A FragmentPagerAdapter with 3 Fragments
Two Fragments, which contain one ListView each
My searches:
Apart from multiple searches on this site, this guy came closest to what I'm seeking:
This guy here Fragmenttransaction in 1 tab of a Fragmentpageradapterhas had the same problem, but it wasn't satisfyingly answered, so I thought I can make a valid question here.
My question:
How can I place two ListViews in one Fragment? The big deal is that for example if the first ListView is bigger than the screen, I don't want the second ListView to show up before the first is completely scrolled down.
Current output:
Currently, both ListViews are in the same position, meaning that one ListView is on top of the other, making both unreadable
I thought that I can maybe use a specified layout for the FragmentTransaction. But I just can't figure out how.
This is the Fragment where I combine my top and bottom ListViews
public class LeaguePageTransactionsAdapter extends Fragment{
Global global_var;
ListView list, list_flat;
List <League> leagues = null, leaguesFlat = null;
ListAdapter adapter = null, adapter_flat = null;
View rootView;
FragmentTransaction fragmentTransaction;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.league_page, container, false);
fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(rootView.getId(), new LeaguePageTop(), "TopFragment");
fragmentTransaction.add(rootView.getId(), new LeaguePageBottom(), "BottomFragment");
fragmentTransaction.commit();
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
}
}
This is corresponding the xml layout file.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
This is one of my two ListViews
public class LeaguePageTop extends Fragment{
ListView list;
List <League> leagues = null;
ListAdapter adapter = null;
View rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.league_page_top, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
list = (ListView) rootView.findViewById(R.id.listView1);
try {
leagues = Leagues_Parser.parse(getActivity().getAssets().open("league_raw.xml"), 0);
} catch (IOException e) {
e.printStackTrace();
}
adapter = new LeagueAdapter (getActivity(), R.layout.list_row, leagues);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
Global.mViewPager.setCurrentItem(1, true);
}
});
}
}
This is the corresponding xml file
<?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" >
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
Thank you very much for reading and thinking about it!
The reason is because you have set the LinearLayout in the XML file you have shown to match_parent which will occupy all available space and then comes your next ListView with it's own LinearLayout (which I presume is set to match_parent as well) and hence there is no space for it to display. FrameLayout and LinearLayout follows an eldest child first approach meaning that the first layout occupies as much space as it requests. Set the LinearLayout you have to wrap_content and I think that should solve your fragment.
Firstly use a view filpper.you can load your first list view in fragment and in your adapterview on item click listener you can flip view by flipper.setdisplayedchild(1) which will show your desired second list.
I am trying to create an item in a ListView that has multiple options; view and edit. I would like to create it in exactly the same way as android's contact system - see below:
I have added the red boxes to illustrate the behaviour I want. If you press within the left red-box, you call the contact. If you press within the right red-box, you send a text message to the contact. I have already created a similar layout in XML, but I am having trouble implementing this functionality in code.
I have tried to create custom android:onClick function calls for the separate layouts within the item, but calling an onClick method only allows you to pass in the View as a parameter, but not the position. Needing the position to use listview.getItemAtPosition function, I tried to use listview.getPositionForView to return the position but found this was extremely unstable and was very easy to return incorrect positioning due to recycling of views.
I then tried to set the item's position as the 'tag' in the getView method of my adapter, like so: convertView.setTag(position). But on the onClick method of my activity, I try and use getTag and cast it back to an integer, and it always returns null, which I find puzzling.
What is the best way of implementing a list populated by items with multiple buttons/layouts on each item?
You can create an onClick event on each views in your row like this :
<?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" >
<TextView
android:id="#+id/text_id"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:onClick="textOnClickEvent"/>
<ImageButton
android:id="#+id/button_id"
android:layout_width="#dimen/width_button"
android:layout_height="match_parent"
android:onClick="imageOnClickEvent"
android:src="#android:drawable/ic_menu_delete" />
</LinearLayout>
Or even, add onClick listeners on each views in the getView method...
more info on this here.
In the list view when you define getview method, this is where you provide all the details of the single list item. There you can mention onlick event of each of the views.
in adapter class, add View.OnClickListener to the getView method:
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if(view == null) {
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
view = layoutInflater.inflate(R.layout.grid_vendor_item, null);
}
final TextView textName = (TextView) view.findViewById(R.id.text_id);
final ImageButton imageProfil = (TextView) view.findViewById(R.id.button_id);
textName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// add your edit codes
}
});
imageProfil.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// add your open prodil codes
}
});
return view;
}
I am working through the Big Nerd Ranch guide for android programming, and I am at the challenge for Chapter 16. The challenge is to make an EmptyView for a ListView, and then make a button on the EmptyView that adds stuff. I got the EmptyView to work but I can't figure out where I should make my button. Here is my code.
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v= super.onCreateView(inflater, parent, savedInstanceState);
inflater.inflate(R.layout.list_frame_layout, parent);
return v;
}
and here is my XML.
<?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="match_parent" >
<ListView
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ListView>
<LinearLayout android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp"
android:text="#string/empty_no_crime" />
<Button
android:id="#+id/empty_new_crime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/empty_new_crime">
</Button>
</LinearLayout>
</FrameLayout>
The book is telling us to use fragments, hence the inflate. I figure the code should be
mNewCrime=(Button)getView().findViewById(R.id.empty_new_crime)
but that isn't working. Any ideas?
Edit*: Hmmm, apparently this also really isn't working that well. When I do add stuff, the EmptyView does not go away, it just gets pushed down while items are listed. Any ideas on how to make the EmptyView go away as soon as I add things?
I had trouble with this challenge at first as well. I over thought it! You have probably solved this issue by now but I thought it would be useful to post an answer for others. The following worked for me:
Create a new XML file specifying the "empty" and "list" views as you have done already.
Modify your existing onCreateView method to inflate the new modified layout which contains the "empty" and "list" views you have defined in your XML.
Create a new button and setup the onClickListener for the button.
Here is the code:
#TargetApi(11)
#Override
// We override the onCreateView to set the subtitle by default if we are rocking >3.0
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
super.onCreateView(inflater, parent, savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
if(mSubtitleVisible){
getActivity().getActionBar().setSubtitle(R.string.subtitle);
}// End inner if
}// End if
View v = inflater.inflate(R.layout.empty_layout, parent, false);
mNewCrimeButton = (Button)v.findViewById(R.id.add_crime);
//Define an click event listener for the button and launch the new crime fragment when clicked
mNewCrimeButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Crime crime = new Crime();
//Get the crimelab from the activity and add the crime
CrimeLab.get(getActivity()).addCrime(crime); //getActivity returns the activity this fragment is attached to
Intent i = new Intent(getActivity(), CrimePagerActivity.class);
startActivityForResult(i,0);
}//End onClick
});
return v;
}// End onCreateView
This should work with your existing xml layout. I hope this helps.
I too struggled initially with this, essentially solving it the same way the above poster did. However my problem was a bit different. I was getting bombed out of the application on startup, because my code that set up the onClick listener looked like this:
Button mCrimeButton = (Button)v.findViewById(R.id.crime_button);
mCrimeButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
initiateCrimeRecord();
}
});
It wasn't until I moved the declaration of mCrimeButton up to the class level making it an instance variable of the class that I was able to successfully execute the app:
public class CrimeListFragment extends ListFragment {
private static final String TAG = "CrimeListFragment";
private ArrayList<Crime> mCrimes;
private boolean mSubtitleVisible;
private Button mCrimeButton;
*
*
*
#TargetApi(11)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_empty_crime_list, parent, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if ( mSubtitleVisible) {
getActivity().getActionBar().setSubtitle(R.string.subtitle);
} else {
getActivity().getActionBar().setSubtitle(null);
}
}
// Set the button up on the empty view
mCrimeButton = (Button)v.findViewById(R.id.crime_button);
mCrimeButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
initiateCrimeRecord();
}
});
return v;
}
I then went back and noticed that in all the other examples in the book, the widgets that get manipulated are declared as private instances of the class. Why is this? Android doesn't allow you to just get a local instance to attach the listener?
I'm developing an app which on start up will show a pre-defined layout like Image(1) in below screenshot.
Now onclick of a button, I want to dynamically add another view like Image(2) in below screenshot to existing view resulting into some like Image(3) in below screenshot.
If onclick is clicked again, Image(2) will be added to existing view resulting into something like Image(4).
How do I achieve this? By searching, I found that it required something like LayoutInflater.addView() like this or LinearLayout.addView() like this.
But I don't know what exactly to use in my case.Also, I'm not trying to add just a single view on button click, but a group of certain views like imageview, 2 textviews,etc. as shown in Image(2).
Any help appreciated.
Edit 1:
I tried something like this:
activity_main.xml
<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" >
<LinearLayout
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:onClick="addViews"
android:text="Add" />
</RelativeLayout>
MainActivity.java
public class MainActivity extends Activity {
LinearLayout main;
int count = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
main = (LinearLayout) findViewById(R.id.main);
}
public void addViews(View view) {
LayoutParams lparams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
Button btn = new Button(this);
btn.setLayoutParams(lparams);
count++;
btn.setText("Hello World : " + count);
main.addView(btn, count);
}
}
It yields something like this:
Now, how do I recognize which button is clicked?
So, you can inflate a view from an XML layout from an Activity like this
View v = View.inflate(this, R.layout.whatever, null);
and then you can add it to your LinearLayout like this:
linearLayout.addView(v);
If you want to access the inner views in your items, you can do it like this:
TextView textView = (TextView) v.findViewById(R.id.textView1);
So, you have to define that group of views in a XML layout, inflate it, manipulate its views as you need, and then add it to your LinearLayout.
Note that you'll need your LinearLayout orientation to be vertical or it won't work as you need.
You can do a lot of things to get that working, but the best approach could be using ListView and ArrayAdapter
Create a class that extends ArrayAdapter<Integer>. There, create a interface to create a Listener.
public interface OnListButtonItemClickedListener{
public int onListButonItemClicked(int position);
}
Define a private OnListButtonItemClickedListener on your ArrayAdapter, and create a public setter.
private OnListButtonItemClickedListener listener;
public void setOnListButtonItemClickedListener(OnListButtonItemClickedListener listener){
this.listener = listener;
}
Define a button inside a Layout in XML. Something like this will do:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dip" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Create a inner ViewHolder class inside your ArrayAdapter class like this:
private class ViewHolder{
public Button b;
}
Override getView and create something like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent){
ViewHandler vh;
if (convertView == null){
convertView = View.inflate(getContext(), R.layout.your_layout, null);
vh = new ViewHolder();
vh.b = (Button) convertView.findViewById(R.id.button1);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
vh.b.setText(String.valueOf(getItem(i).intValue()));
vh.b.setOnClickListener(new OnClickListener(){
public void onClick(View v){
if (listener != null){
listener.onListButonItemClicked(getItem(position).intValue());
}
}
});
return convertView;
}
Set the adapter to a ListView, and when you want to add a new one, just do this:
adapter.add(i);
adapter.notifyDataSetChanged();
Maybe you can try this
Create a custom view that extends LinearLayout, orientation: vertical.
Create another custom view, this view will be the "row". This view is the container of the image, text in bold and text below.
In the first custom view that extends linearLayout, you can addView(View v) and pass the other custom view, the row.
Am I clear? It is something similar that adapter and listview works.
I don't know if this fits whatever your app's purpose is, but try using a ListView with an ArrayAdapter. You will begin with an empty ListView, as defined in XML, then add items to a connected ArrayAdapter in code. Each time the button is pressed, you can add an image into the ArrayAdapter and call .notifyDataSetChanged(). This should stack them just as shown in your images above. You can also use a secondary LinearLayout to group items.
EDIT:
To determine which button is clicked you simply reference the View passed to your addViews(View v) method. You can either switch on the id:
public void addViews(View v){
int id = v.getId();
switch(id){
case R.id.id1:
//do something
case R.id.id2:
//do something
}
}
Or you can get the text from the button in a similar manner by using:
public void addViews(View v){
Button b = (Button)v; //make sure you know that it will be a button
String s = b.getText().toString();
switch(s){
case "test case 1":
//do something
case "test case 2":
//do something
}
}
If you aren't sure how many buttons there will be, I would suggest using the strings method. If the buttons won't have names that are convenient to parse in this manner, store references to the buttons as keys in a HashMap and use a String as the value. You can then plug in the button, get the string and do whatever is needed.
I'm new to developing with android. I have a grid contained in a LinearLayout and each item which makes up the grid is a button. I want this LinearLayout to be invisible when the user pushes any of these buttons.
This is my 'home' layout shell:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView/>
<LinearLayout> //<-- this is the layout I want to hide
<TextView/>
<GridView/>
</LinearLayout>
</LinearLayout>
And this is the onClick method which I've set up in MyArrayAdapter (used to inflate buttons)
#Override
public void onClick(View v) {
View convertView = activity.getLayoutInflater().inflate(R.layout.layout_home, null);
LinearLayout ll_options = (LinearLayout) convertView.findViewById(R.id.ll_options);
ll_options.setVisibility(View.INVISIBLE);
}
I think it should work but when I test it, nothing happens.
I found a similar question but it doesn't solve my problem.
Why are you inflating a layout here?:
View convertView = activity.getLayoutInflater().inflate(R.layout.layout_home, null);
Just do:
View v = activity.findViewById(R.id.ll_options);
v.setVisibility(View.INVISIBLE);
You create a new view which is not in the visible view hierarchy until you add it there, and then you hide that. So you hide something invisible.
Instead, try:
#Override
public void onClick(View v) {
findViewById(R.id.ll_options).setVisibility(View.INVISIBLE);
}
which should IMO work. It searches for the ll_options view inside the visible (global) view hierarchy of your activity and hides that.
EDIT:
Where is your button? Is it in the same layout-file?
You inflate a new layout and hide the LinearLayout there, but this new layout is never used. Be sure you have access to the contentView in your listener.