5

I am working on integrating Twitter in an app and while all works as it should I am stumped on the setOnItemClickListener() not triggering when a ListView item has a link in it. It works just fine when an item does not have a link (URL) in it.

Clicking on the URL itself opens the web page in a Browser.

Please see the screenshots added as reference at the end of the post.

It is a custom ListView that employs a BaseAdapter. I am not sure which piece of code to put in but on being pointed to a code block that the folks here may need, I will add it immediately.

The idea behind needing to ignore the links (URLs) in an item is to provide a functionality that shows the tweet details when a user clicks on one. Something similar to what the Twitter Android app does.

So what do I do to make the setOnItemClickListener() ignore the links in items?

UPDATED:

Okay. SO I am not sure if it is relevant to the question, but, from a combination of a few solutions from SO which led me to the TweetLanes Open Source project, I have managed to get a few things working. But unfortunately, it doesn't address my primary question.

How do I make the setOnItemClickListener() ignore the links in an item so I can click it and show the details in another Activity and yet, when I click on a link, not trigger the setOnItemClickListener()? I keep getting partial solutions in every attempt I make. But at times, when I click on a link, the setOnItemClickListener() triggers too.

This is how it the flow looks at the moment:

enter image description here

In the top two screenshots, it works as it should. Not clicking on a link after all.

In the bottom two, however, when I click on the @ibnlive link, it shows the Profile for the user (@ibnlive). This part is derived from the TweetLanes source. The problem is, the click listener is also triggered. This is one of the solutions I am trying out. In this case, I have commented out the setOnItemClickListener() and am using a OnClickListener() on the TextView. This is the one method which has partial success so far.

SSL
  • 278
  • 2
  • 17
  • Post your custom layout you are using in Listview.And if possible set the property of views in custom listview like this - Focusable = false and focusableInTouchMode = false.If it doesnt work then post your layout of listview. – AndiM Apr 17 '13 at 10:12
  • I have tried your layout in listview.It works fine. – AndiM Apr 17 '13 at 10:38
  • @Meghs: With a link (URL) in the `TextView`? It still doesn't at my end. – SSL Apr 17 '13 at 10:43
  • Yes with a link..What are you doing on click of URL???I think you need both click event on URL and also click event of item.Am I right..??? – AndiM Apr 17 '13 at 10:48
  • @Meghs: Correct. I need them both to function independently. But I am not doing anything for the click on the URL. That is taken care of automatically by this `android:autoLink="web|email"`. – SSL Apr 17 '13 at 10:51
  • Try to set property focusable and focusableInTouchMOde to false of textview that have URL.Thats the only option I can see.Otherwise override onclick of URL texview in getview method. – AndiM Apr 17 '13 at 11:00
  • You probably want to take a look at this: http://stackoverflow.com/a/14093635/833622 Based on it, I advice you to fix the file TwitterLinkify.java. (the function that sets the link movement) – Sherif elKhatib Apr 22 '13 at 09:54
  • @SherifelKhatib: Please post your comment as an answer. The link you posted worked like a charm. :-) And sorry for replying this late. I was trying out different solutions and combinations of them. I was avoiding creating a custom `TextView` _for no good reason_. But that did it for me. :-) – SSL Apr 24 '13 at 12:01
  • Thank you to everyone who attempted to help me. :-) – SSL Apr 24 '13 at 12:02
  • @SSL please take a look at the answer and tell me if what I added as a Solution (without having to extend TextView) works or not. – Sherif elKhatib Apr 24 '13 at 12:34

5 Answers5

2

In order to support listItem's click events and supporting links inside records, you should set android:descendantFocusability="blocksDescendants" at the top-level layout of your list-record's xml.

waqaslam
  • 67,549
  • 16
  • 165
  • 178
  • set this attribute at the top parent layout of your xml used in inflating list item. – waqaslam Apr 17 '13 at 10:05
  • Not sure I follow. But this is what I have done after your previous comment. I have 2 XML's. One for the `ListView` titled `the_list.xml` and one for the custom rows titled `timeline_items.xml`. I add the attribute you posted in the top level `LinearLayout` in the `timeline_items.xml` and **not** in the `the_list.xml`. But still the same result. Please correct if I am wrong. – SSL Apr 17 '13 at 10:12
  • perhaps it would be better if you paste your related xml code too. – waqaslam Apr 17 '13 at 10:13
  • did you try cleaning and refreshing your project? – waqaslam Apr 17 '13 at 10:29
  • Ahh. That, I didn't. Let me do it. – SSL Apr 17 '13 at 10:33
  • 1
    This should work based on what you said. Please see this thread [here](https://code.google.com/p/android/issues/detail?id=3414) – rarp Apr 22 '13 at 05:55
  • Thank you for offering your help on this sticky problem. :-) – SSL Apr 24 '13 at 12:04
1

That's because link is clickable and listItem is also clickable, so here, link takes the focus and hence listItem cannot be clicked.

You just need to set :

Set all items android:focusable="false"

and android:focusableInTouchMode="false" of listItem.

Intrications
  • 16,782
  • 9
  • 50
  • 50
Shrikant Ballal
  • 7,067
  • 7
  • 41
  • 61
1

Have you tried the next code (based on this link) :

textView.setMovementMethod(null);

?


EDIT: here's a working solution:

textView.setOnTouchListener(new OnTouchListener() 
    {
    @Override
    public boolean onTouch(final View v, final MotionEvent event) 
        {
        if (event.getAction() == MotionEvent.ACTION_UP)
          {
          // <=handle clicking here
          }
        return true;
        }
   });
Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • Yup. Already in the adapter. I have also tried using another `txtStatusPhotoMessage.setMovementMethod(LinkMovementMethod.getInstance());` but both end up with the same result. :-( – SSL Apr 22 '13 at 05:53
  • @SSL Have you somehow got a workaround for this? I want to try it out myself. Just to clarify, you wish that the item will be selected instead of opening the link, right? – android developer Apr 22 '13 at 08:45
  • @SSL Updated answer. Now it works, but it's a weird solution. – android developer Apr 22 '13 at 09:18
  • I think another solution could be to remove the clickableSpans if there are any , and for each URLSpan, set its onClick event to call the clicking on the item instead . – android developer Apr 22 '13 at 09:29
  • Actually, I want to select the item when not clicked on a link to show the tweet details. But if a link in the item is clicked, that should open too. But without regsitering the click in `ListView's` `setOnItemClickListener()` or the Widget's (TextView) `OnClickListener()`. Right now using the `OnClickListener()` I have got it working, but clicking on a link triggers the listener too. – SSL Apr 22 '13 at 09:40
  • @SSL So you can set it to be ignored in case the link was clicked, by overriding the onClick of the URLSpan of the textView. – android developer Apr 22 '13 at 10:00
  • Thank you for offering your help on this sticky problem. :-) – SSL Apr 24 '13 at 12:04
1

You probably want to take a look at babay's answer on ListView: TextView with LinkMovementMethod makes list item unclickable?

He presents a TextView that issues this problem basically by introducing a different LinkMovementMethod:

public static class LocalLinkMovementMethod extends LinkMovementMethod{
    static LocalLinkMovementMethod sInstance;


    public static LocalLinkMovementMethod getInstance() {
        if (sInstance == null)
            sInstance = new LocalLinkMovementMethod();

        return sInstance;
    }

    @Override
    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
        int action = event.getAction();

        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= widget.getTotalPaddingLeft();
            y -= widget.getTotalPaddingTop();

            x += widget.getScrollX();
            y += widget.getScrollY();

            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                }

                if (widget instanceof TextViewFixTouchConsume){
                    ((TextViewFixTouchConsume) widget).linkHit = true;
                }
                return true;
            } else {
                Selection.removeSelection(buffer);
                Touch.onTouchEvent(widget, buffer, event);
                return false;
            }
        }
        return Touch.onTouchEvent(widget, buffer, event);
    }
}

Solution NOT TESTED

Based on it, I advice you to fix the file TwitterLinkify.java (the function that sets the link movement) like this:

private static final void addLinkMovementMethod(TextView t) {
    MovementMethod m = t.getMovementMethod();

    if ((m == null) || !(m instanceof LocalLinkMovementMethod)) {
        if (t.getLinksClickable()) {
            t.setMovementMethod(LocalLinkMovementMethod.getInstance());
        }
    }
}

Thanks

Community
  • 1
  • 1
Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
  • I choose to extend a `TextView`. In all honesty, I did not try extending just the `LinkMovementMethod` as you posted. – SSL Apr 24 '13 at 13:13
0

Please have a look at this .

text_url.setText(Html.fromHtml(url.toString().trim()));
        Linkify.addLinks(text_url, Linkify.ALL);

This is the line i am using to show the url in list view. if you do the above lines in your getview the link will become blue color with the underline automatically.if you click that one it will open the browser automatically.

Hope this will help you.

EDIT

Hi have a look at this edited answer. i have verified it. it will open the correct url . hope this will help you.

 String url="www.google.com";
        String name="@sampleuser";  
     textview1.setText(Html.fromHtml("<a href='http://"+url+"'>http://"+name+"</a>")); 
     textview1.setMovementMethod(LinkMovementMethod.getInstance());

EDIT 2 Hi have a look at this sample. hope this will help you .

package com.example.listwithclick;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {


    ListView listView1;
    Activity activity;
    ArrayList<String>urls=new ArrayList<String>();
    ArrayList<String>name=new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity=this;

        urls.add("www.google.com");
        name.add("@googleuser");

        urls.add("www.yahoo.com");
        name.add("@yahoouser");
        urls.add("www.facebook.com");
        name.add("@facebookuser");
        urls.add("www.linkedin.com");
        name.add("@linkedinuser");

        listView1=(ListView)findViewById(R.id.listView1);
        listView1.setAdapter(new MyAddapter(MainActivity.this));

    }

    @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;
    }
     class MyAddapter extends BaseAdapter {
            Context rContext;
            private LayoutInflater rInflater;

            public MyAddapter(Context c) {

                rInflater = LayoutInflater.from(c);

                rContext = c;

            }      

            public MyAddapter(Activity imagebinding) {
                // TODO Auto-generated constructor stub

                activity = imagebinding;        

                rContext = imagebinding;
                rInflater = LayoutInflater.from(imagebinding);
                rContext = imagebinding;
                rInflater = (LayoutInflater) activity
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);



            }

            @Override
            public int getCount() {
                // TODO Auto-generated method stub  


                return urls.size();
            }

            @Override
            public Object getItem(int arg0) {
                // TODO Auto-generated method stub
                return null;
            }

            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return 0;
            }

            @Override
            public View getView(final int position, View convertView,
                    ViewGroup parent) {
                // TODO Auto-generated method stub
                convertView = rInflater.inflate(R.layout.child, null);
                final MyDat mydat = new MyDat();                

                mydat.textview = (TextView) convertView.findViewById(R.id.textview_name);
                mydat.textview.setText(Html.fromHtml("<a href='http://"+urls.get(position).toString()+"'>"+name.get(position).toString()+"</a>")); 
                mydat.textview.setMovementMethod(LinkMovementMethod.getInstance());

                return convertView;
            }

            class MyDat {


                TextView  textview;


            }

        }

}
itsrajesh4uguys
  • 4,610
  • 3
  • 20
  • 31
  • I am using a different method. In my adapter, I am using `TwitterLinkify.addLinks(holder.txtStatusPhotoMessage, Linkify.ALL);` where the `TwitterLinkify` is from the TweetLanes source. I need that to handle clicks on **@someuser** and show the profile in my own app. – SSL Apr 22 '13 at 05:36
  • No fella. I don't have a problem opening links. Links, emails, phone numbers and my custom method for showing Twitter Profile's work absolutely fine. My problem is neither the `onClickListener()` nor the `setOnItemClickListener()` trigger when the item has any links in it. – SSL Apr 22 '13 at 07:21
  • setonItemClickListener will work for whole child.. so you need to use setonclicklistener to click the child. you need to use position . for that. – itsrajesh4uguys Apr 22 '13 at 07:31
  • And all of that has been tried. Please see the image attached in the OP that already illustrates this behavior. – SSL Apr 22 '13 at 07:35
  • Thank you for offering your help on this sticky problem. :-) – SSL Apr 24 '13 at 12:03