精华内容
下载资源
问答
  • 2021-06-12 04:39:26

    有没有办法链接ListView中包含的特定TextView?我尝试使用android:autoLink="all",但这不起作用。我得到了一个脱离背景错误。

    重要的是要注意:ListView是我在ViewFlipper中的第二个视图。

    我也尝试过:

    View mItemView = mAdapter.getView(2, null, null);

    TextView infoText = (TextView) mItemView.findViewById(R.id.rowText2);

    Linkify.addLinks(infoText, Linkify.ALL);

    将适配器绑定到ListView并切换View后。没有运气。

    这是堆栈跟踪:

    06-03 21:19:25.180: ERROR/AndroidRuntime(1214): Uncaught handler: thread main exiting due to uncaught exception

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.app.ApplicationContext.startActivity(ApplicationContext.java:550)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.content.ContextWrapper.startActivity(ContextWrapper.java:248)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.text.style.URLSpan.onClick(URLSpan.java:62)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.text.method.LinkMovementMethod.onTouchEvent(LinkMovementMethod.java:216)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.widget.TextView.onTouchEvent(TextView.java:6560)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.View.dispatchTouchEvent(View.java:3709)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.app.Activity.dispatchTouchEvent(Activity.java:2061)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.os.Handler.dispatchMessage(Handler.java:99)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.os.Looper.loop(Looper.java:123)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at android.app.ActivityThread.main(ActivityThread.java:4363)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at java.lang.reflect.Method.invokeNative(Native Method)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at java.lang.reflect.Method.invoke(Method.java:521)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

    06-03 21:19:25.219: ERROR/AndroidRuntime(1214): at dalvik.system.NativeStart.main(Native Method)

    任何想法?

    提前致谢!!!

    更多相关内容
  • 自动连结 自动链接是CKEditor的插件,用于在键入类似URL的字符串时自动生成...cp -r plugins/autolink your_dir_path/ckeditor/plugins 将此插件添加到您的ckeditor的config.js中,如下所示: config . extraPlugins
  • 使用TextView的autoLink属性设置超链接,用工具类方式和自定义View方式两种方式修改超链接显示样式和链接地址的点击事件。
  • 自动链接 Java库,用于从纯文本中提取诸如URL和电子邮件地址之类的链接。 明智的做法是知道链接在何处结束(例如使用尾随标点符号)。 介绍 您可能会想:“为此我需要一个库吗?我可以为此编写一个正则表达式!...
  • zotero-autolink zotero-autolink 插件允许 Zotero 用户将他们链接的文件附件存储在独立的网络存储服务上,例如 Dropbox 或私人 ftp 服务器。 使用 zotero-autolink,可以在平板电脑或手机上通过 Zotero 网页界面...
  • npm install remark-autolink-headings 采用 假设我们有以下 markdown 文件example.md : # Lorem ipsum :sleepy_face: ## dolor—sit—amet ### consectetur & adipisicing #### elit ##### elit 我们的...
  • 在TextView 中设置autoLink 属性可以自动识别WebURL,电话号码,电子邮件地址添加下划线改变字体颜色并实现点击事件,支持自动识别的类型:android:autoLink=“web” 匹配Web URL。android:autoLink=“phone” 匹配...

    在TextView 中设置autoLink 属性可以自动识别Web

    URL,电话号码,电子邮件地址添加下划线改变字体颜色并实现点击事件,支持自动识别的类型:

    android:autoLink=“web” 匹配Web URL。

    android:autoLink=“phone” 匹配电话号码

    android:autoLink=“email” 匹配电子邮件地址

    android:autoLink=“map” 匹配地理位置

    android:autoLink=“all” 匹配所有可用的模式

    android:autoLink=“none” 不匹配任何类型

    也可以类似这样的设置 android:autoLink=“web|phone” 表示匹配web URL 和手机号

    上面的属性也可以通过java 代码的形式对TextView 设置

    setAutoLinkMask(int mask) 进行设置

    1

    设置的参数分别是:

    Linkify.WEB_URLS 匹配Web UR

    Linkify.PHONE_NUMBERS 匹配电话号码

    Linkify.EMAIL_ADDRESSES 匹配电子邮件地址

    Linkify.MAP_ADDRESSES 地理位置匹配

    Linkify.ALL 匹配所有可用的模式

    设置完antoLink属性,点击TextView中的链接时会跳转的对应的界面,比如点击网页的链接会跳转到系统的默认的浏览器界面,点击手机号会进入拨打电话界面,但是这都是系统默认的,我们可不可以进行拦截处理,跳转到我们指定的界面呢,当然是可以的。下面是我的拦截处理的方法。

    继承 MovementMethod ,这里我们先看一下MovementMethod的源码,它的源码比较少

    public class LinkMovementMethod extends

    ScrollingMovementMethod {

    private static final int

    CLICK = 1;

    private static final int

    UP = 2;

    private static final int

    DOWN = 3;

    @Override

    public boolean

    canSelectArbitrarily() {

    return true;

    }

    @Override

    protected boolean

    handleMovementKey(TextView widget, Spannable buffer, int

    keyCode,

    int

    movementMetaState, KeyEvent event) {

    switch (keyCode) {

    case

    KeyEvent.KEYCODE_DPAD_CENTER:

    case

    KeyEvent.KEYCODE_ENTER:

    if

    (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {

    if (event.getAction() == KeyEvent.ACTION_DOWN

    &&

    event.getRepeatCount() == 0

    && action(CLICK, widget, buffer)) {

    return

    true;

    }

    }

    break;

    }

    return super.handleMovementKey(widget, buffer,

    keyCode, movementMetaState, event);

    }

    @Override

    protected boolean

    up(TextView widget, Spannable buffer) {

    if (action(UP, widget, buffer)) {

    return

    true;

    }

    return super.up(widget, buffer);

    }

    @Override

    protected boolean

    down(TextView widget, Spannable buffer) {

    if (action(DOWN, widget, buffer)) {

    return

    true;

    }

    return super.down(widget, buffer);

    }

    @Override

    protected boolean

    left(TextView widget, Spannable buffer) {

    if (action(UP, widget, buffer)) {

    return

    true;

    }

    return super.left(widget, buffer);

    }

    @Override

    protected boolean

    right(TextView widget, Spannable buffer) {

    if (action(DOWN, widget, buffer)) {

    return

    true;

    }

    return super.right(widget, buffer);

    }

    private boolean

    action(int what, TextView widget, Spannable buffer) {

    Layout layout = widget.getLayout();

    int padding = widget.getTotalPaddingTop()

    +

    widget.getTotalPaddingBottom();

    int areaTop = widget.getScrollY();

    int areaBot = areaTop + widget.getHeight() -

    padding;

    int lineTop =

    layout.getLineForVertical(areaTop);

    int lineBot =

    layout.getLineForVertical(areaBot);

    int first = layout.getLineStart(lineTop);

    int last = layout.getLineEnd(lineBot);

    ClickableSpan[] candidates =

    buffer.getSpans(first, last, ClickableSpan.class);

    int a =

    Selection.getSelectionStart(buffer);

    int b = Selection.getSelectionEnd(buffer);

    int selStart = Math.min(a, b);

    int selEnd = Math.max(a, b);

    if (selStart < 0) {

    if

    (buffer.getSpanStart(FROM_BELOW) >= 0) {

    selStart = selEnd =

    buffer.length();

    }

    }

    if (selStart > last)

    selStart =

    selEnd = Integer.MAX_VALUE;

    if (selEnd < first)

    selStart =

    selEnd = -1;

    switch (what) {

    case CLICK:

    if

    (selStart == selEnd) {

    return false;

    }

    ClickableSpan[] link = buffer.getSpans(selStart, selEnd,

    ClickableSpan.class);

    if

    (link.length != 1)

    return false;

    link[0].onClick(widget);

    break;

    case UP:

    int

    bestStart, bestEnd;

    bestStart

    = -1;

    bestEnd =

    -1;

    for (int i

    = 0; i < candidates.length; i++) {

    int end =

    buffer.getSpanEnd(candidates[i]);

    if (end < selEnd ||

    selStart == selEnd) {

    if (end > bestEnd) {

    bestStart

    = buffer.getSpanStart(candidates[i]);

    bestEnd =

    end;

    }

    }

    }

    if

    (bestStart >= 0) {

    Selection.setSelection(buffer, bestEnd, bestStart);

    return true;

    }

    break;

    case DOWN:

    bestStart

    = Integer.MAX_VALUE;

    bestEnd =

    Integer.MAX_VALUE;

    for (int i

    = 0; i < candidates.length; i++) {

    int start =

    buffer.getSpanStart(candidates[i]);

    if (start > selStart ||

    selStart == selEnd) {

    if (start < bestStart) {

    bestStart

    = start;

    bestEnd =

    buffer.getSpanEnd(candidates[i]);

    }

    }

    }

    if

    (bestEnd < Integer.MAX_VALUE) {

    Selection.setSelection(buffer, bestStart, bestEnd);

    return true;

    }

    break;

    }

    return false;

    }

    @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[] links = buffer.getSpans(off, off,

    ClickableSpan.class);

    if

    (links.length != 0) {

    if (action ==

    MotionEvent.ACTION_UP) {

    links[0].onClick(widget);

    } else if (action ==

    MotionEvent.ACTION_DOWN) {

    Selection.setSelection(buffer,

    buffer.getSpanStart(links[0]),

    buffer.getSpanEnd(links[0]));

    }

    return true;

    } else

    {

    Selection.removeSelection(buffer);

    }

    }

    return super.onTouchEvent(widget, buffer,

    event);

    }

    @Override

    public void

    initialize(TextView widget, Spannable text) {

    Selection.removeSelection(text);

    text.removeSpan(FROM_BELOW);

    }

    @Override

    public void

    onTakeFocus(TextView view, Spannable text, int dir) {

    Selection.removeSelection(text);

    if ((dir & View.FOCUS_BACKWARD) != 0)

    {

    text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT);

    } else {

    text.removeSpan(FROM_BELOW);

    }

    }

    public static

    MovementMethod getInstance() {

    if (sInstance == null)

    sInstance

    = new LinkMovementMethod();

    return sInstance;

    }

    private static

    LinkMovementMethod sInstance;

    private static Object

    FROM_BELOW = new NoCopySpan.Concrete();

    }

    在上面的这段代码中处理界面跳转的只有这一行

    links[0].onClick(widget);我们要实现自己的跳转只要在自定义的LinkMovementMethod的这一行进行处理就行了。

    先定义一个替换links[0].onClick(widget);的接口

    public interface LinkClickListener {

    boolean

    onLinkClick(String mURL);

    }

    定义一个LinkMovementMethod的子类

    LinkMovementMethodEx,在onTouchEvent方法中做了判断,在我们应用自己处理的情况,就不在走系统的默认处理,只有我们自己不处理的情况下才走系统的。

    public class LinkMovementMethodEx extends LinkMovementMethod

    {

    private

    LinkClickListener listener;

    public

    LinkMovementMethodEx(LinkClickListener listener) {

    this.listener = listener;

    }

    @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[] links = buffer.getSpans(off, off,

    ClickableSpan.class);

    if

    (links.length != 0) {

    if (action ==

    MotionEvent.ACTION_UP) {

    if (links[0] instanceof URLSpan) {

    URLSpan

    url = (URLSpan) links[0];

    if

    (listener != null && listener.onLinkClick(url.getURL()))

    {

    return true;

    } else

    {

    links[0].onClick(widget);

    }

    }

    } else if (action ==

    MotionEvent.ACTION_DOWN) {

    Selection.setSelection(buffer,

    buffer.getSpanStart(links[0]),

    buffer.getSpanEnd(links[0]));

    }

    return true;

    } else

    {

    Selection.removeSelection(buffer);

    }

    }

    return super.onTouchEvent(widget, buffer,

    event);

    }

    }

    在项目中的引用

    public class MainActivity extends Activity {

    private String TAG =

    MainActivity.class.getSimpleName();

    private TextView

    title;

    @Override

    protected void

    onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    title = findViewById(R.id.tv_content);

    title.setText(" 10086 中国移动的 这是百度的

    https://www.baidu.com/");

    title.setMovementMethod(new

    LinkMovementMethodEx(new LinkClickListener() {

    @Override

    public

    boolean onLinkClick(String mURL) {

    //在这里执行直接的处理逻辑并将返回值设置为true

    Log.i(TAG, "onLinkClick: " +

    mURL);

    return false;

    }

    }));

    }

    }

    展开全文
  • 首先调用 Linkify.addLinks 方法解析 autolink 的相关属性 判断是否 mLinksClickable mLinksClickable && !textCanBeSelected() ,若返回 true, 设置 setMovementMethod 我们先来看一下 Linkify 类, ...

    }

    }

    }

    • 首先调用 Linkify.addLinks 方法解析 autolink 的相关属性

    • 判断是否 mLinksClickable mLinksClickable && !textCanBeSelected() ,若返回 true, 设置 setMovementMethod

    我们先来看一下 Linkify 类, 里面定义了几个常量, 分别对应 web , email ,phone ,map,他们的值是位上错开的,这样定义的好处是

    • 方便组合多种值

    • 组合值之后不会丢失状态,即可以获取是否含有某种状态, web, email, phone , map

    public class Linkify {

    public static final int WEB_URLS = 0x01;

    public static final int EMAIL_ADDRESSES = 0x02;

    public static final int PHONE_NUMBERS = 0x04;

    public static final int MAP_ADDRESSES = 0x08;

    }

    看一下 linkify 的 addLinks 方法

    • 根据 mask 的标志位,进行相应的正则表达式进行匹配,找到 text 里面的相应的 WEB_URLS, EMAIL_ADDRESSES, PHONE_NUMBERS, MAP_ADDRESSES. 并将相应的文本从 text 里面移除,封装成 LinkSpec,并添加到 links 里面

    • 遍历 links,设置相应的 URLSpan

    pri

    《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

    【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

    vate static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,

    @Nullable Context context) {

    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 links = new ArrayList();

    / / 根据正则表达式提取 text 里面相应的 WEB_URLS,并且从 text 移除

    if ((mask & WEB_URLS) != 0) {

    gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL,

    new String[] { “http://”, “https://”, “rtsp://” },

    sUrlMatchFilter, null);

    }

    if ((mask & EMAIL_ADDRESSES) != 0) {

    gatherLinks(links, text, Patterns.AUTOLINK_EMAIL_ADDRESS,

    new String[] { “mailto:” },

    null, null);

    }

    if ((mask & PHONE_NUMBERS) != 0) {

    gatherTelLinks(links, text, context);

    }

    if ((mask & MAP_ADDRESSES) != 0) {

    gatherMapLinks(links, text);

    }

    pruneOverlaps(links);

    if (links.size() == 0) {

    return false;

    }

    // 遍历 links,设置相应的 URLSpan

    for (LinkSpec link: links) {

    applyLink(link.url, link.start, link.end, text);

    }

    return true;

    }

    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);

    }

    接下来我们一起来看一下这个 URLSpan 是何方神圣,它继承了 ClickableSpan(注意下文会用到它),并且重写了 onClick 方法,我们可以看到在 onClick 方法里面,他通过相应的 intent 取启动相应的 activity。因此,我们可以断定 autolink 的自动跳转是在这里处理的。

    public class URLSpan extends ClickableSpan implements ParcelableSpan {

    private final String mURL;

    /**

    • Constructs a {@link URLSpan} from a url string.

    • @param url the url string

    */

    public URLSpan(String url) {

    mURL = url;

    }

    /**

    • Constructs a {@link URLSpan} from a parcel.

    */

    public URLSpan(@NonNull Parcel src) {

    mURL = src.readString();

    }

    @Override

    public int getSpanTypeId() {

    return getSpanTypeIdInternal();

    }


    @Override

    public void onClick(View widget) {

    Uri uri = Uri.parse(getURL());

    Context context = widget.getContext();

    Intent intent = new Intent(Intent.ACTION_VIEW, uri);

    intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());

    try {

    context.startActivity(intent);

    } catch (ActivityNotFoundException e) {

    Log.w(“URLSpan”, "Actvity was not found for intent, " + intent.toString());

    }

    }

    }

    解决了 autolink 属性点击事件在哪里响应了,接下来我们一起看一下 URLSpan 的 onClick 方法是在哪里调用的。

    autolink 的 onclick 事件是在哪里被调用的

    我们先来复习一下 View 的事件分发机制:

    • dispatchTouchEvent ,这个方法主要是用来分发事件的

    • onInterceptTouchEvent,这个方法主要是用来拦截事件的(需要注意的是ViewGroup才有这个方法,- View没有onInterceptTouchEvent这个方法

    • onTouchEvent 这个方法主要是用来处理事件的

    requestDisallowInterceptTouchEvent(true),这个方法能够影响父View是否拦截事件,true 表示父 View 不拦截事件,false 表示父 View 拦截事件

    因此我们猜测 URLSpan 的 onClick 事件是在 TextView 的 onTouchEvent 事件里面调用的。下面让我们一起来看一下 TextView 的 onTouchEvent 方法

    @Override

    public boolean onTouchEvent(MotionEvent event) {

    final int action = event.getActionMasked();

    if (mEditor != null) {

    mEditor.onTouchEvent(event);

    if (mEditor.mSelectionModifierCursorController != null

    && mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {

    return true;

    }

    }

    final boolean superResult = super.onTouchEvent(event);

    /*

    • Don’t handle the release after a long press, because it will move the selection away from

    • whatever the menu action was trying to affect. If the long press should have triggered an

    • insertion action mode, we can now actually show it.

    */

    if (mEditor != null && mEditor.mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {

    mEditor.mDiscardNextActionUp = false;

    if (mEditor.mIsInsertionActionModeStartPending) {

    mEditor.startInsertionActionMode();

    mEditor.mIsInsertionActionModeStartPending = false;

    }

    return superResult;

    }

    final boolean touchIsFinished = (action == MotionEvent.ACTION_UP)

    && (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();

    if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()

    && mText instanceof Spannable && mLayout != null) {

    boolean handled = false;

    if (mMovement != null) {

    handled |= mMovement.onTouchEvent(this, mSpannable, event);

    }

    final boolean textIsSelectable = isTextSelectable();

    if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && textIsSelectable) {

    // The LinkMovementMethod which should handle taps on links has not been installed

    // on non editable text that support text selection.

    // We reproduce its behavior here to open links for these.

    ClickableSpan[] links = mSpannable.getSpans(getSelectionStart(),

    getSelectionEnd(), ClickableSpan.class);

    if (links.length > 0) {

    links[0].onClick(this);

    handled = true;

    }

    }

    if (touchIsFinished && (isTextEditable() || textIsSelectable)) {

    // Show the IME, except when selecting in read-only text.

    final InputMethodManager imm = InputMethodManager.peekInstance();

    viewClicked(imm);

    if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {

    imm.showSoftInput(this, 0);

    }

    // The above condition ensures that the mEditor is not null

    mEditor.onTouchUpEvent(event);

    handled = true;

    }

    if (handled) {

    return true;

    }

    }

    return superResult;

    }

    首先如果 mEditor != null 会将touch事件交给mEditor处理,这个 mEditor 其实是和 EditText 有关系的,没有使用 EditText 这里应该是不会被创建的。

    去除 mEditor != null 的相关逻辑之后,剩下的相关代码主要如下:

    final boolean touchIsFinished = (action == MotionEvent.ACTION_UP)

    && (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();

    if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()

    && mText instanceof Spannable && mLayout != null) {

    boolean handled = false;

    if (mMovement != null) {

    handled |= mMovement.onTouchEvent(this, mSpannable, event);

    }

    final boolean textIsSelectable = isTextSelectable();

    if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && textIsSelectable) {

    // The LinkMovementMethod which should handle taps on links has not been installed

    // on non editable text that support text selection.

    // We reproduce its behavior here to open links for these.

    ClickableSpan[] links = mSpannable.getSpans(getSelectionStart(),

    getSelectionEnd(), ClickableSpan.class);

    if (links.length > 0) {

    links[0].onClick(this);

    handled = true;

    }

    }

    if (touchIsFinished && (isTextEditable() || textIsSelectable)) {

    // Show the IME, except when selecting in read-only text.

    final InputMethodManager imm = InputMethodManager.peekInstance();

    viewClicked(imm);

    if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {

    imm.showSoftInput(this, 0);

    }

    // The above condition ensures that the mEditor is not null

    mEditor.onTouchUpEvent(event);

    handled = true;

    }

    if (handled) {

    return true;

    }

    }

    首先我们先来看一下, mMovement 是否可能为 null,若不为 null,则会调用 handled |= mMovement.onTouchEvent(this, mSpannable, event) 方法。

    找啊找,发现在 setText 里面有调用这一段代码,setMovementMethod(LinkMovementMethod.getInstance()); 即 mLinksClickable && !textCanBeSelected() 为 true 的时候给 TextView 设置 MovementMethod。

    查看 TextView 的源码我们容易得知 mLinksClickable 的值默认为 true, 而 textCanBeSelected 方法会返回 false,即 mLinksClickable && !textCanBeSelected() 为 true,这个时候会给 TextView 设置 setMovementMethod。 因此在 TextView 的 onTouchEvent 方法中,若 autoLink 等于 true,并且 text 含有 email,phone, webAddress 等的时候,会调用 mMovement.onTouchEvent(this, mSpannable, event) 方法。

    if (Linkify.addLinks(s2, mAutoLinkMask)) {

    text = s2;

    type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;

    /*

    • We must go ahead and set the text before changing the

    • movement method, because setMovementMethod() may call

    • setText() again to try to upgrade the buffer type.

    */

    setTextInternal(text);

    // Do not change the movement method for text that support text selection as it

    // would prevent an arbitrary cursor displacement.

    if (mLinksClickable && !textCanBeSelected()) {

    setMovementMethod(LinkMovementMethod.getInstance());

    }

    }

    boolean textCanBeSelected() {

    // prepareCursorController() relies on this method.

    // If you change this condition, make sure prepareCursorController is called anywhere

    // the value of this condition might be changed.

    // 默认 mMovement 为 null

    if (mMovement == null || !mMovement.canSelectArbitrarily()) return false;

    return isTextEditable()

    || (isTextSelectable() && mText instanceof Spannable && isEnabled());

    }

    ok ,我们一起在来看一下 mMovement 的 onTouchEvent 方法

    MovementMethod 是一个借口,实现子类有 ArrowKeyMovementMethod, LinkMovementMethod, ScrollingMovementMethod 。

    这里我们先来看一下 LinkMovementMethod 的 onTouchEvent 方法

    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[] links = buffer.getSpans(off, off, ClickableSpan.class);

    if (links.length != 0) {

    ClickableSpan link = links[0];

    if (action == MotionEvent.ACTION_UP) {

    if (link instanceof TextLinkSpan) {

    ((TextLinkSpan) link).onClick(

    widget, TextLinkSpan.INVOCATION_METHOD_TOUCH);

    } else {

    link.onClick(widget);

    }


    }

    这里我们重点关注代码 20 - 31 行,可以看到,他会先取出所有的 ClickableSpan,而我们的 URLSpan 正是 ClickableSpan 的子类,接着判断是否是 ACTION_UP 事件,然后调用 onClick 事件。因此,ClickableSpan 的 onClick 方法是在 ACTION_UP 事件中调用的,跟我们的长按事件没半毛钱关系。

    重要的事情说三遍

    ClickableSpan 的 onClick 方法是在 ACTION_UP 事件中调用的

    ClickableSpan 的 onClick 方法是在 ACTION_UP 事件中调用的

    ClickableSpan 的 onClick 方法是在 ACTION_UP 事件中调用的

    知道了 ClickableSpan 的 onClick 方法是在 ACTION_UP 事件中调用的,下面让我们一起来看一下怎样解决 TextView 中 autolink 与 clickableSpan 与长按事件的冲突。


    解决思路


    展开全文
  • rails_autolink 描述: 这是从rails中提取的auto_link方法。 `auto_link`方法已从Rails 3.1版本的Rails中删除。 该宝石旨在弥合移民人群的鸿沟。 特点: 默认情况下,auto_link返回已清理的html_safe字符串。...
  • [](()autolink 的 onclick 事件是在哪里被调用的 我们先来复习一下 View 的事件分发机制: dispatchTouchEvent ,这个方法主要是用来分发事件的 onInterceptTouchEvent,这个方法主要是用来拦截事件的(需要注意的...

    if (mAutoLinkMask != 0) {

    Spannable s2;

    if (type == BufferType.EDITABLE || text instanceof Spannable) {

    s2 = (Spannable) text;

    } else {

    s2 = mSpannableFactory.newSpannable(text);

    }

    if (Linkify.addLinks(s2, mAutoLinkMask)) {

    text = s2;

    type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;

    /*

    • We must go ahead and set the text before changing the

    • movement method, because setMovementMethod() may call

    • setText() again to try to upgrade the buffer type.

    */

    setTextInternal(text);

    // Do not change the movement method for text that support text selection as it

    // would prevent an arbitrary cursor displacement.

    if (mLinksClickable && !textCanBeSelected()) {

    setMovementMethod(LinkMovementMethod.getInstance());

    }

    }

    }

    • 首先调用 Linkify.addLinks 方法解析 autolink 的相关属性

    • 判断是否 mLinksClickable mLinksClickable && !textCanBeSelected() ,若返回 true, 设置 setMovementMethod

    我们先来看一下 Linkify 类, 里面定义了几个常量, 分别对应 web , email ,phone ,map,他们的值是位上错开的,这样定义的好处是

    • 方便组合多种值

    • 组合值之后不会丢失状态,即可以获取是否含有某种状态, web, email, phone , map

    public class Linkify {

    public static final int WEB_URLS = 0x01;

    public static final int EMAIL_ADDRESSES = 0x02;

    public static final int PHONE_NUMBERS = 0x04;

    public static final int MAP_ADDRESSES = 0x08;

    }

    看一下 linkify 的 addLinks 方法

    • 根据 mask 的标志位,进行相应的正则表达式进行匹配,找到 text 里面的相应的 WEB_URLS, EMAIL_ADDRESSES, PHONE_NUMBERS, MAP_ADDRESSES. 并将相应的文本从 text 里面移除,封装成 LinkSpec,并添加到 links 里面

    • 遍历 links,设置相应的 URLSpan

    private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,

    @Nullable Context context) {

    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 links = new ArrayList();

    / / 根据正则表达式提取 text 里面相应的 WEB_URLS,并且从 text 移除

    if ((mask & WEB_URLS) != 0) {

    gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL,

    new String[] { “http://”, “https://”, “rtsp://” },

    sUrlMatchFilter, null);

    }

    if ((mask & EMAIL_ADDRESSES) != 0) {

    gatherLinks(links, text, Patterns.AUTOLINK_EMAIL_ADDRESS,

    new String[] { “mailto:” },

    null, null);

    }

    if ((mask & PHONE_NUMBERS) != 0) {

    gatherTelLinks(links, text, context);

    }

    if ((mask & MAP_ADDRESSES) != 0) {

    gatherMapLinks(links, text);

    }

    pruneOverlaps(links);

    if (links.size() == 0) {

    return false;

    }

    // 遍历 links,设置相应的 URLSpan

    for (LinkSpec link: links) {

    applyLink(link.url, link.start, link.end, text);

    }

    return true;

    }

    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);

    }

    接下来我们一起来看一下这个 URLSpan 是何方神圣,它继承了 ClickableSpan(注意下文会用到它),并且重写了 onClick 方法,我们可以看到在 onClick 方法里面,他通过相应的 intent 取启动相应的 activity。因此,我们可以断定 autolink 的自动跳转是在这里处理的。

    public class URLSpan extends ClickableSpan implements ParcelableSpan {

    private final String mURL;

    /**

    • Constructs a {@link URLSpan} from a url string.

    • @param url the url string

    */

    public URLSpan(String url) {

    mURL = url;

    }

    /**

    • Constructs a {@link URLSpan} from a parcel.

    */

    public URLSpan(@NonNull Parcel src) {

    mURL = src.readString();

    }

    @Override

    public int getSpanTypeId() {

    return getSpanTypeIdInternal();

    }


    @Override

    public void onClick(View widget) {

    Uri uri = Uri.parse(getURL());

    Context context = widget.getContext();

    Intent intent = new Intent(Intent.ACTION_VIEW, uri);

    intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());

    try {

    context.startActivity(intent);

    } catch (ActivityNotFoundException e) {

    Log.w(“URLSpan”, "Actvity was not found for intent, " + intent.toString());

    }

    }

    }

    解决了 autolink 属性点击事件在哪里响应了,接下来我们一起看一下 URLSpan 的 onClick 方法是在哪里调用的。

    [](()autolink 的 onclick 事件是在哪里被调用的

    我们先来复习一下 View 的事件分发机制:

    • dispatchTouchEvent ,这个方法主要是用来分发事件的

    • onInterceptTouchEvent,这个方法主要是用来拦截事件的(需要注意的是ViewGroup才有这个方法,- View没有onInterceptTouchEvent这个方法

    • onTouchEvent 这个方法主要是用来处理事件的

    requestDisallowInterceptTouchEvent(true),这个方法能够影响父View是否拦截事件,true 表示父 View 不拦截事件,false 表示父 View 拦截事件

    因此我们猜测 URLS 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》开源 pan 的 onClick 事件是在 TextView 的 onTouchEvent 事件里面调用的。下面让我们一起来看一下 TextView 的 onTouchEvent 方法

    @Override

    public boolean onTouchEvent(MotionEvent event) {

    final int action = event.getActionMasked();

    if (mEditor != null) {

    mEditor.onTouchEvent(event);

    if (mEditor.mSelectionModifierCursorController != null

    && mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {

    return true;

    }

    }

    final boolean superResult = super.onTouchEvent(event);

    /*

    • Don’t handle the release after a long press, because it will move the selection away from

    • whatever the menu action was trying to affect. If the long press should have triggered an

    • insertion action mode, we can now actually show it.

    */

    if (mEditor != null && mEditor.mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {

    mEditor.mDiscardNextActionUp = false;

    if (mEditor.mIsInsertionActionModeStartPending) {

    mEditor.startInsertionActionMode();

    mEditor.mIsInsertionActionModeStartPending = false;

    }

    return superResult;

    }

    final boolean touchIsFinished = (action == MotionEvent.ACTION_UP)

    && (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();

    if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()

    && mText instanceof Spannable && mLayout != null) {

    boolean handled = false;

    if (mMovement != null) {

    handled |= mMovement.onTouchEvent(this, mSpannable, event);

    }

    final boolean textIsSelectable = isTextSelectable();

    if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && textIsSelectable) {

    // The LinkMovementMethod which should handle taps on links has not been installed

    // on non editable text that support text selection.

    // We reproduce its behavior here to open links for these.

    ClickableSpan[] links = mSpannable.getSpans(getSelectionStart(),

    getSelectionEnd(), ClickableSpan.class);

    if (links.length > 0) {

    links[0].onClick(this);

    handled = true;

    }

    }

    if (touchI Android开源项目:ali1024.coding.net/public/P7/Android/git sFinished && (isTextEditable() || textIsSelectable)) {

    // Show the IME, except when selecting in read-only text.

    final InputMethodManager imm = InputMethodManager.peekInstance();

    viewClicked(imm);

    if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {

    imm.showSoftInput(this, 0);

    }

    // The above condition ensures that the mEditor is not null

    mEditor.onTouchUpEvent(event);

    handled = true;

    }

    if (handled) {

    return true;

    }

    }

    return superResult;

    }

    首先如果 mEditor != null 会将touch事件交给mEditor处理,这个 mEditor 其实是和 EditText 有关系的,没有使用 EditText 这里应该是不会被创建的。

    去除 mEditor != null 的相关逻辑之后,剩下的相关代码主要如下:

    final boolean touchIsFinished = (action == MotionEvent.ACTION_UP)

    && (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();

    if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()

    && mText instanceof Spannable && mLayout != null) {

    boolean handled = false;

    if (mMovement != null) {

    handled |= mMovement.onTouchEvent(this, mSpannable, event);

    }

    结语

    • 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
    • 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
    • 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
    • OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。


    vent(this, mSpannable, event);

    }

    结语

    • 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
    • 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
    • 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
    • OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。

    [外链图片转存中…(img-oUPRA0fG-1649943193170)]

    [外链图片转存中…(img-DqB7tblT-1649943193171)]

    展开全文
  • Jekyll :: Autolink电子邮件 为您的Jekyll网站自动链接电子邮件。 安装 添加到您的Gemfile : gem 'jekyll-autolink_email' 添加到您的_config.yml : gems : - jekyll-autolink_email 用法 在任何html页面或...
  • AutoLink.rar

    2020-04-06 18:44:19
    本资源是GitHub上AutoLink,自动玩连连看软件的相关文件。 Git Hub 项目地址:https://github.com/ztmajor/AutoLink 包括了雷电模拟器下载器,单机连连看.apk,训练好的模型(alexnet.pth)和训练好的模型参数 ...
  • autolink-开源

    2021-05-01 06:51:03
    perl工具,用于通过本地自定义自动维护多台配置相似的unix机器。 可逐步安装。 基于文件。
  • 1.电话号码识别Android SDK中,TextView提供了一个autoLink属性来帮助我们识别各种各样的链接,我们只需要将autoLink属性设置为"phone",就能轻易识别出电话号码。这个属性在8.1之前的机器上是可以正常工作...
  • I have a TextView like this.android:id="@+id/text_auto_linkify"android:layout_width="match_parent"android:layout_height="wrap_content"android:autoLink="web"android:text="@string/link_text_auto" />...
  • 我们知道,在布局文件中设置textview的autolink及其类型,这时textivew上会显示link的颜色,并且文字下面会有一条下划线,表示可以点击。而在我们在点击textview时,应用将根据我们所设置的类型跳转到对应的界面。...
  • autolink-0.6.0.jar

    2022-02-23 22:07:47
    java运行依赖jar包
  • TextView的autoLink属性设置超链接问题

    千次阅读 2018-10-16 15:18:16
    最近接到类似的这种需求,网上查找资料学习到了TextView的autoLink属性,那autoLink是怎么使用的呢?为什么设置autoLink就可以实现TextView的超链接,底层是怎么实现的呢?TextView显示时自动排版不整齐,怎么解决呢...
  • npm install rehype-autolink-headings 用 假设我们有以下文件fragment.html : < h1> Lorem ipsum :sleepy_face: < h2> dolor—sit—amet < h3> consectetur & adipisicing < h4> elit < h5> elit 我们...
  • autolink.cr:Crystal的自动链接
  • 我有一个listview 。 并且行布局中包含很少的布局。 在行布局中,我有一个TextView ,我想在其上启用自动链接当我启用自动链接时,链接工作正常但...cardview="http://schemas.android.com/apk/res-auto" android:id="@+id/card_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/White" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" cardview:cardCornerRadius="5dp" cardview:cardElevation="5dp" cardview:cardBackgroundColor="@color/White" cardview:cardUseCompatPadding="true" > android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:descendantFocusability="blocksDescendants"> android:id="@+id/message_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="10dp" android:layout_marginBottom="10dp" android:text="M" android:gravity="top" android:textAppearance="?android:attr/textAppearanceMedium" android:focusable="false" android:focusableInTouchMode="false" android:autoLink="web" android:background="@color/Blue" /> android:id="@+id/Share" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/message_text" android:focusable="true" android:layout_margin="5dp" android:background="@drawable/share3" android:adjustViewBounds="True" /> android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/Share" android:layout_alignBottom="@+id/Share" android:layout_alignParentRight="true" android:layout_margin="5dp" android:text="Timexxxxx" android:layout_gravity="right" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="@color/Time" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@+id/time" android:layout_alignParentLeft="true" android:paddingBottom="2dp" android:paddingLeft="5dp" android:paddingRight="5dp" android:paddingTop="2dp" android:layout_marginTop="10dp" android:scaleType="fitXY" android:src="@android:drawable/divider_horizontal_bright" /> 有人请帮忙吗...
  • 我们知道,在布局文件中设置textview的autolink及其类型,这时textivew上会显示link的颜色,并且文字下面会有一条下划线,表示可以点击。而在我们在点击textview时,应用将根据我们所设置的类型跳转到对应的界面。...
  • 关键字概要说明 如何使用调度管理 上传和下载RobotFramework用例 微信群 目前AutoLink专用讨论微信群已经建立,为严格控制准入条件的群,加入条件请参见:AutoLink微信群 数据与用例分离的标准项目结构 支持的关键...
  • roam-autolink-crx插件

    2021-04-03 02:50:46
    语言:English (United States) 跟踪和自动化漫游研究中链接/页面中的单词 这是漫游的扩展,允许用户指定某些单词以在键入时自动形成链接。 使用方法:...
  • AutoLink开源自动化测试集成解决方案.docx
  • 为 Microsoft 的 Business Contact Manager 自动链接。 作为一项服务安装,该程序会在添加新联系人时为所有用户添加自动链接。
  • java运行依赖jar包

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,782
精华内容 2,312
关键字:

autolink

友情链接: ChengFaBiao.zip