Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/213.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Linkify web和@提及都在同一文本视图中_Android_Textview_Linkify - Fatal编程技术网

Android Linkify web和@提及都在同一文本视图中

Android Linkify web和@提及都在同一文本视图中,android,textview,linkify,Android,Textview,Linkify,好的,我昨天问了这个问题: 我的@提及链接正确。但是为了让它正常工作,我不得不将android:autoLink=web从我的xml中取出,用于TextView。所以现在我得到了@提及的链接,但它不再链接URL。我尝试了两个单独的Linkify.addLinks调用,如下所示: mentionFilter = new TransformFilter() { public final String transformUrl(final Matcher match, String url)

好的,我昨天问了这个问题:

我的@提及链接正确。但是为了让它正常工作,我不得不将android:autoLink=web从我的xml中取出,用于TextView。所以现在我得到了@提及的链接,但它不再链接URL。我尝试了两个单独的Linkify.addLinks调用,如下所示:

mentionFilter = new TransformFilter() {
    public final String transformUrl(final Matcher match, String url) {
        return match.group(1);
    }
};

// Match @mentions and capture just the username portion of the text.
//pattern = Pattern.compile("@([A-Za-z0-9_-]+)");
pattern = Pattern.compile("(@[a-zA-Z0-9_]+)");
scheme = "http://twitter.com/";

tweetTxt = (TextView) v.findViewById(R.id.tweetTxt);


Linkify.addLinks(tweetTxt, pattern, scheme, null, mentionFilter);
Linkify.addLinks(tweetTxt, Linkify.WEB_URLS);
<TextView 
    android:id="@+id/tweet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textStyle="bold"
    android:textColorLink="#449def"/>
但最后一个被调用的是被应用的。有谁能告诉我如何使它既能链接@提及,又能自动链接URL


编辑以澄清更多代码。

tweetTxt是您正在链接的输入字符串还是指向TextView对象的句柄? 如果是输入字符串,那么您只是用addLinks的最终调用的输出覆盖TextView。根据你的观察,我猜情况就是这样


在这两种情况下,您都需要将TextView传递给addLinks。在内部,Linkify将从TextView中提取已跨越的缓冲区,并使用该缓冲区,以便对addLinks的多次调用是累积的。WikiNotes示例传递文本视图,您也应该这样做:

我找到了一种方法来实现这一点。这有点不太对劲,但它完成了任务。如果有人知道更合适的方法,请告诉我

为了让它工作起来,我给自己制作了一个Linkify类的副本,并编辑了处理电话号码链接的部分,改为使用@提及链接

我改变了这一点:

if ((mask & PHONE_NUMBERS) != 0) {
            gatherLinks(links, text, Regex.PHONE_PATTERN,
                new String[] { "tel:" },
                sPhoneNumberMatchFilter, sPhoneNumberTransformFilter);
        }
为此:

if ((mask & PHONE_NUMBERS) != 0) {
    gatherLinks(links, text, Pattern.compile("@([A-Za-z0-9_-]+)"),
        new String[] { "http://www.twitter.com/" },
        null, null);
}
我将这个类称为MyLinkify,并在我的活动中使用此代码来应用链接

MyLinkify.addLinks(tweetTxt, Linkify.ALL);
为了构建MyLink类,我还必须在我的项目中添加一个Regex类的副本


我把这作为一个答案,以防任何其他人寻找这个效果找到这个线程。我意识到这可能不是让它发挥作用的最佳方式。如果有人知道更好的方法,请将其添加到这里,我会选择它作为这个问题的实际答案。

好的,终于有时间在Linkify类中正确地添加@title和hashtags。而不是仅仅覆盖一些其他类型的链接以使其工作

这个类就像普通的Linkify一样工作,但也可以做这两件事

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.use.your.own.package;


import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.style.URLSpan;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.webkit.WebView;
import android.widget.TextView;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *  Linkify take a piece of text and a regular expression and turns all of the
 *  regex matches in the text into clickable links.  This is particularly
 *  useful for matching things like email addresses, web urls, etc. and making
 *  them actionable.
 *
 *  Alone with the pattern that is to be matched, a url scheme prefix is also
 *  required.  Any pattern match that does not begin with the supplied scheme
 *  will have the scheme prepended to the matched text when the clickable url
 *  is created.  For instance, if you are matching web urls you would supply
 *  the scheme <code>http://</code>.  If the pattern matches example.com, which
 *  does not have a url scheme prefix, the supplied scheme will be prepended to
 *  create <code>http://example.com</code> when the clickable url link is
 *  created.
 */


public class LinkifyWithTwitter {
     /**
     *  Bit field indicating that web URLs should be matched in methods that
     *  take an options mask
     */
    public static final int WEB_URLS = 0x01;

    /**
     *  Bit field indicating that email addresses should be matched in methods
     *  that take an options mask
     */
    public static final int EMAIL_ADDRESSES = 0x02;

    /**
     *  Bit field indicating that phone numbers should be matched in methods that
     *  take an options mask
     */
    public static final int PHONE_NUMBERS = 0x04;

    /**
     *  Bit field indicating that twitter @mentions should be matched in methods that
     *  take an options mask
     */
    public static final int AT_MENTIONS = 0x05;

    /**
     *  Bit field indicating that #hash-tags should be matched in methods that
     *  take an options mask
     */
    public static final int HASH_TAGS = 0x06;

    /**
     *  Bit field indicating that street addresses should be matched in methods that
     *  take an options mask
     */
    public static final int MAP_ADDRESSES = 0x08;

    /**
     *  Bit mask indicating that all available patterns should be matched in
     *  methods that take an options mask
     */
    public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS | AT_MENTIONS| HASH_TAGS |MAP_ADDRESSES;

    /**
     * Don't treat anything with fewer than this many digits as a
     * phone number.
     */
    private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5;

    /**
     *  Filters out web URL matches that occur after an at-sign (@).  This is
     *  to prevent turning the domain name in an email address into a web link.
     */
    public static final MatchFilter sUrlMatchFilter = new MatchFilter() {
        public final boolean acceptMatch(CharSequence s, int start, int end) {
            if (start == 0) {
                return true;
            }

            if (s.charAt(start - 1) == '@') {
                return false;
            }

            return true;
        }
    };

    /**
     *  Filters out URL matches that don't have enough digits to be a
     *  phone number.
     */
    public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() {
        public final boolean acceptMatch(CharSequence s, int start, int end) {
            int digitCount = 0;

            for (int i = start; i < end; i++) {
                if (Character.isDigit(s.charAt(i))) {
                    digitCount++;
                    if (digitCount >= PHONE_NUMBER_MINIMUM_DIGITS) {
                        return true;
                    }
                }
            }
            return false;
        }
    };

    /**
     *  Transforms matched phone number text into something suitable
     *  to be used in a tel: URL.  It does this by removing everything
     *  but the digits and plus signs.  For instance:
     *  &apos;+1 (919) 555-1212&apos;
     *  becomes &apos;+19195551212&apos;
     */
    public static final TransformFilter sPhoneNumberTransformFilter = new TransformFilter() {
        public final String transformUrl(final Matcher match, String url) {
            return Regex.digitsAndPlusOnly(match);
        }
    };

    /**
     *  MatchFilter enables client code to have more control over
     *  what is allowed to match and become a link, and what is not.
     *
     *  For example:  when matching web urls you would like things like
     *  http://www.example.com to match, as well as just example.com itelf.
     *  However, you would not want to match against the domain in
     *  support@example.com.  So, when matching against a web url pattern you
     *  might also include a MatchFilter that disallows the match if it is
     *  immediately preceded by an at-sign (@).
     */
    public interface MatchFilter {
        /**
         *  Examines the character span matched by the pattern and determines
         *  if the match should be turned into an actionable link.
         *
         *  @param s        The body of text against which the pattern
         *                  was matched
         *  @param start    The index of the first character in s that was
         *                  matched by the pattern - inclusive
         *  @param end      The index of the last character in s that was
         *                  matched - exclusive
         *
         *  @return         Whether this match should be turned into a link
         */
        boolean acceptMatch(CharSequence s, int start, int end);
    }

    /**
     *  TransformFilter enables client code to have more control over
     *  how matched patterns are represented as URLs.
     *
     *  For example:  when converting a phone number such as (919)  555-1212
     *  into a tel: URL the parentheses, white space, and hyphen need to be
     *  removed to produce tel:9195551212.
     */
    public interface TransformFilter {
        /**
         *  Examines the matched text and either passes it through or uses the
         *  data in the Matcher state to produce a replacement.
         *
         *  @param match    The regex matcher state that found this URL text
         *  @param url      The text that was matched
         *
         *  @return         The transformed form of the URL
         */
        String transformUrl(final Matcher match, String url);
    }

    /**
     *  Scans the text of the provided Spannable and turns all occurrences
     *  of the link types indicated in the mask into clickable links.
     *  If the mask is nonzero, it also removes any existing URLSpans
     *  attached to the Spannable, to avoid problems if you call it
     *  repeatedly on the same text.
     */
    public static final boolean addLinks(Spannable text, int mask) {
        if (mask == 0) {
            return false;
        }

        URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class);

        for (int i = old.length - 1; i >= 0; i--) {
            text.removeSpan(old[i]);
        }

        ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();

        if ((mask & WEB_URLS) != 0) {
            gatherLinks(links, text, Regex.WEB_URL_PATTERN,
                new String[] { "http://", "https://" },
                sUrlMatchFilter, null);
        }

        if ((mask & EMAIL_ADDRESSES) != 0) {
            gatherLinks(links, text, Regex.EMAIL_ADDRESS_PATTERN,
                new String[] { "mailto:" },
                null, null);
        }

        if ((mask & PHONE_NUMBERS) != 0) {
            gatherLinks(links, text, Regex.PHONE_PATTERN,
                new String[] { "tel:" },
                sPhoneNumberMatchFilter, sPhoneNumberTransformFilter);
        }

        if((mask & AT_MENTIONS) != 0){
            gatherLinks(links, text, Pattern.compile("@([A-Za-z0-9_-]+)"),
                    new String[] { "http://www.twitter.com/" },
                    null, null);
        }

        if((mask & HASH_TAGS) != 0){
            TransformFilter hashTagFilter = new TransformFilter() {
                public final String transformUrl(final Matcher match, String url) {
                    return match.group(0).replaceAll("#", "%23");
                }
            };

            gatherLinks(links, text, Pattern.compile("#([A-Za-z0-9_-]+)"),
                new String[] { "http://twitter.com/#!/search/" },
                null,hashTagFilter);
        }

        if ((mask & MAP_ADDRESSES) != 0) {
            gatherMapLinks(links, text);
        }

        pruneOverlaps(links);

        if (links.size() == 0) {
            return false;
        }

        for (LinkSpec link: links) {
            applyLink(link.url, link.start, link.end, text);
        }

        return true;
    }

    /**
     *  Scans the text of the provided TextView and turns all occurrences of
     *  the link types indicated in the mask into clickable links.  If matches
     *  are found the movement method for the TextView is set to
     *  LinkMovementMethod.
     */
    public static final boolean addLinks(TextView text, int mask) {
        if (mask == 0) {
            return false;
        }

        CharSequence t = text.getText();

        if (t instanceof Spannable) {
            if (addLinks((Spannable) t, mask)) {
                addLinkMovementMethod(text);
                return true;
            }

            return false;
        } else {
            SpannableString s = SpannableString.valueOf(t);

            if (addLinks(s, mask)) {
                addLinkMovementMethod(text);
                text.setText(s);

                return true;
            }

            return false;
        }
    }

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

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

    /**
     *  Applies a regex to the text of a TextView turning the matches into
     *  links.  If links are found then UrlSpans are applied to the link
     *  text match areas, and the movement method for the text is changed
     *  to LinkMovementMethod.
     *
     *  @param text         TextView whose text is to be marked-up with links
     *  @param pattern      Regex pattern to be used for finding links
     *  @param scheme       Url scheme string (eg <code>http://</code> to be
     *                      prepended to the url of links that do not have
     *                      a scheme specified in the link text
     */
    public static final void addLinks(TextView text, Pattern pattern, String scheme) {
        addLinks(text, pattern, scheme, null, null);
    }

    /**
     *  Applies a regex to the text of a TextView turning the matches into
     *  links.  If links are found then UrlSpans are applied to the link
     *  text match areas, and the movement method for the text is changed
     *  to LinkMovementMethod.
     *
     *  @param text         TextView whose text is to be marked-up with links
     *  @param p            Regex pattern to be used for finding links
     *  @param scheme       Url scheme string (eg <code>http://</code> to be
     *                      prepended to the url of links that do not have
     *                      a scheme specified in the link text
     *  @param matchFilter  The filter that is used to allow the client code
     *                      additional control over which pattern matches are
     *                      to be converted into links.
     */
    public static final void addLinks(TextView text, Pattern p, String scheme,
            MatchFilter matchFilter, TransformFilter transformFilter) {
        SpannableString s = SpannableString.valueOf(text.getText());

        if (addLinks(s, p, scheme, matchFilter, transformFilter)) {
            text.setText(s);
            addLinkMovementMethod(text);
        }
    }

    /**
     *  Applies a regex to a Spannable turning the matches into
     *  links.
     *
     *  @param text         Spannable whose text is to be marked-up with
     *                      links
     *  @param pattern      Regex pattern to be used for finding links
     *  @param scheme       Url scheme string (eg <code>http://</code> to be
     *                      prepended to the url of links that do not have
     *                      a scheme specified in the link text
     */
    public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) {
        return addLinks(text, pattern, scheme, null, null);
    }

    /**
     *  Applies a regex to a Spannable turning the matches into
     *  links.
     *
     *  @param s            Spannable whose text is to be marked-up with
     *                      links
     *  @param p            Regex pattern to be used for finding links
     *  @param scheme       Url scheme string (eg <code>http://</code> to be
     *                      prepended to the url of links that do not have
     *                      a scheme specified in the link text
     *  @param matchFilter  The filter that is used to allow the client code
     *                      additional control over which pattern matches are
     *                      to be converted into links.
     */
    public static final boolean addLinks(Spannable s, Pattern p,
            String scheme, MatchFilter matchFilter,
            TransformFilter transformFilter) {
        boolean hasMatches = false;
        String prefix = (scheme == null) ? "" : scheme.toLowerCase();
        Matcher m = p.matcher(s);

        while (m.find()) {
            int start = m.start();
            int end = m.end();
            boolean allowed = true;

            if (matchFilter != null) {
                allowed = matchFilter.acceptMatch(s, start, end);
            }

            if (allowed) {
                String url = makeUrl(m.group(0), new String[] { prefix },
                                     m, transformFilter);

                applyLink(url, start, end, s);
                hasMatches = true;
            }
        }

        return hasMatches;
    }

    private static final void applyLink(String url, int start, int end, Spannable text) {
        URLSpan span = new URLSpan(url);

        text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    private static final String makeUrl(String url, String[] prefixes,
            Matcher m, TransformFilter filter) {
        if (filter != null) {
            url = filter.transformUrl(m, url);
        }

        boolean hasPrefix = false;

        for (int i = 0; i < prefixes.length; i++) {
            if (url.regionMatches(true, 0, prefixes[i], 0,
                                  prefixes[i].length())) {
                hasPrefix = true;

                // Fix capitalization if necessary
                if (!url.regionMatches(false, 0, prefixes[i], 0,
                                       prefixes[i].length())) {
                    url = prefixes[i] + url.substring(prefixes[i].length());
                }

                break;
            }
        }

        if (!hasPrefix) {
            url = prefixes[0] + url;
        }

        return url;
    }

    private static final void gatherLinks(ArrayList<LinkSpec> links,
            Spannable s, Pattern pattern, String[] schemes,
            MatchFilter matchFilter, TransformFilter transformFilter) {
        Matcher m = pattern.matcher(s);

        while (m.find()) {
            int start = m.start();
            int end = m.end();

            if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) {
                LinkSpec spec = new LinkSpec();
                String url = makeUrl(m.group(0), schemes, m, transformFilter);

                spec.url = url;
                spec.start = start;
                spec.end = end;

                links.add(spec);
            }
        }
    }

    private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
        String string = s.toString();
        String address;
        int base = 0;

        while ((address = WebView.findAddress(string)) != null) {
            int start = string.indexOf(address);

            if (start < 0) {
                break;
            }

            LinkSpec spec = new LinkSpec();
            int length = address.length();
            int end = start + length;

            spec.start = base + start;
            spec.end = base + end;
            string = string.substring(end);
            base += end;

            String encodedAddress = null;

            try {
                encodedAddress = URLEncoder.encode(address,"UTF-8");
            } catch (UnsupportedEncodingException e) {
                continue;
            }

            spec.url = "geo:0,0?q=" + encodedAddress;
            links.add(spec);
        }
    }

    private static final void pruneOverlaps(ArrayList<LinkSpec> links) {
        Comparator<LinkSpec>  c = new Comparator<LinkSpec>() {
            public final int compare(LinkSpec a, LinkSpec b) {
                if (a.start < b.start) {
                    return -1;
                }

                if (a.start > b.start) {
                    return 1;
                }

                if (a.end < b.end) {
                    return 1;
                }

                if (a.end > b.end) {
                    return -1;
                }

                return 0;
            }

            public final boolean equals(Object o) {
                return false;
            }
        };

        Collections.sort(links, c);

        int len = links.size();
        int i = 0;

        while (i < len - 1) {
            LinkSpec a = links.get(i);
            LinkSpec b = links.get(i + 1);
            int remove = -1;

            if ((a.start <= b.start) && (a.end > b.start)) {
                if (b.end <= a.end) {
                    remove = i + 1;
                } else if ((a.end - a.start) > (b.end - b.start)) {
                    remove = i + 1;
                } else if ((a.end - a.start) < (b.end - b.start)) {
                    remove = i;
                }

                if (remove != -1) {
                    links.remove(remove);
                    len--;
                    continue;
                }

            }

            i++;
        }
    }
}

class LinkSpec {
    String url;
    int start;
    int end;
}
使用以下代码:

 TextView textView =  (TextView) findViewById(R.id.hello);
        String str = "@aman_vivek how are u  #aman_vivek <http://www.google.com> <http://www.tekritisoftware.com>";
        textView.setText(str);
        Pattern wikiWordMatcher = Pattern.compile("(@[a-zA-Z0-9_]+)");
        String wikiViewURL =    "http://www.twitter.com/";
        Linkify.addLinks(textView, wikiWordMatcher, wikiViewURL);


        Pattern wikiWordMatcher1 = Pattern.compile("\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
        Linkify.addLinks(textView, wikiWordMatcher1, null);

以下是我链接所有Twitter链接、标签和URL的代码:

TextView tweet = (TextView) findViewById(R.id.tweet);

TransformFilter filter = new TransformFilter() {
    public final String transformUrl(final Matcher match, String url) {
        return match.group();
    }
};

Pattern mentionPattern = Pattern.compile("@([A-Za-z0-9_-]+)");
String mentionScheme = "http://www.twitter.com/";
Linkify.addLinks(tweet, mentionPattern, mentionScheme, null, filter);

Pattern hashtagPattern = Pattern.compile("#([A-Za-z0-9_-]+)");
String hashtagScheme = "http://www.twitter.com/search/";
Linkify.addLinks(tweet, hashtagPattern, hashtagScheme, null, filter);

Pattern urlPattern = Patterns.WEB_URL;
Linkify.addLinks(tweet, urlPattern, null, null, filter);

我必须先Linkify.ALL,然后再链接@提及,这样它才能工作


另外,不要在XML布局文件的TextView中使用“android:autoLink”

TextView textView = (TextView) findViewById(R.id.tweet);

Pattern atMentionPattern = Pattern.compile("@([A-Za-z0-9_]+)");
String atMentionScheme = "http://twitter.com/";

TransformFilter transformFilter = new TransformFilter() {
        //skip the first character to filter out '@'
        public String transformUrl(final Matcher match, String url) {
                return match.group(1);
        }
};

Linkify.addLinks(textView, Linkify.ALL);
Linkify.addLinks(textView, atMentionPattern, atMentionScheme, null, transformFilter);
我的文本视图如下所示:

mentionFilter = new TransformFilter() {
    public final String transformUrl(final Matcher match, String url) {
        return match.group(1);
    }
};

// Match @mentions and capture just the username portion of the text.
//pattern = Pattern.compile("@([A-Za-z0-9_-]+)");
pattern = Pattern.compile("(@[a-zA-Z0-9_]+)");
scheme = "http://twitter.com/";

tweetTxt = (TextView) v.findViewById(R.id.tweetTxt);


Linkify.addLinks(tweetTxt, pattern, scheme, null, mentionFilter);
Linkify.addLinks(tweetTxt, Linkify.WEB_URLS);
<TextView 
    android:id="@+id/tweet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textStyle="bold"
    android:textColorLink="#449def"/>

tweetTxt是文本视图。如果尝试传入字符串,Linkify.addLinks将不起作用。复制此类后,正则表达式将显示错误。它是一个库吗?@typedef Regex是android.text.util.Regex.java类,另外,请参阅@Suraj cAlso的答案,不要在XML布局文件的TextView中使用“android:autoLink”,不要在XML布局文件的TextView中使用“android:autoLink”,而要使用Linkify.addLinks。希望这有助于为某些人节省一些时间,无论你从下面给出的答案中得出什么结论