= array(); } $post['classname'] = 'post'; } function comment_format(&$post) { global $conf, $uid, $gid, $forumlist; if (empty($post)) return; $forum = $post['fid'] ? forum_read($post['fid']) : ''; $thread = well_thread_read_cache($post['tid']); if ($thread) { //$post['fid'] = $thread['fid']; $post['closed'] = $thread['closed']; $post['subject'] = $thread['subject']; $post['url'] = $thread['url']; } else { $post['closed'] = 0; $post['subject'] = lang('thread_not_exists'); $post['url'] = ''; } $post['create_date_fmt'] = humandate($post['create_date']); //$post['message'] = stripslashes(htmlspecialchars_decode($post['message'])); $user = user_read_cache($post['uid']); $post['username'] = array_value($user, 'username'); $post['user_avatar_url'] = array_value($user, 'avatar_url'); $post['user'] = $user ? user_safe_info($user) : user_guest(); isset($post['floor']) || $post['floor'] = 0; // 权限判断 $post['allowupdate'] = 2 == array_value($forum, 'comment', 0) && ($uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowupdate')); $post['allowdelete'] = group_access($gid, 'allowuserdelete') && $uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowdelete'); $post['user_url'] = url('user-' . $post['uid'] . ($post['uid'] ? '' : '-' . $post['pid'])); if ($post['files'] > 0) { list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($post['pid']); // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 if (2 == $conf['attach_on']) { foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $post['message'] = FALSE !== strpos($post['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $post['message']) : $post['message']; } } $post['filelist'] = $filelist; } else { $post['filelist'] = array(); } $post['classname'] = 'post'; } function comment_format_message(&$val) { global $conf; if (empty($val)) return; // 使用云储存 if (1 == $conf['attach_on'] && 1 == $val['attach_on']) { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } elseif (2 == $conf['attach_on'] && 2 == $val['attach_on']) { // 使用图床 list($attachlist, $imagelist, $filelist) = well_attach_find_by_tid($val['tid']); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $val['message'] = FALSE !== strpos($val['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $val['message']) : $val['message']; } } else { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } //$val['message'] = stripslashes(htmlspecialchars_decode($val['message'])); } // 把内容中使用了云储存的附件链接替换掉 function comment_message_replace_url($pid, $message) { global $conf; if (0 == $conf['attach_on']) { $message = FALSE !== strpos($message, '="../upload/') ? str_replace('="../upload/', '="upload/', $message) : $message; $message = FALSE !== strpos($message, '="/upload/') ? str_replace('="/upload/', '="upload/', $message) : $message; } elseif (1 == $conf['attach_on']) { // 使用云储存 $message = str_replace('="' . $conf['cloud_url'] . 'upload/', '="upload/', $message); } elseif (2 == $conf['attach_on']) { // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($pid); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换回相对链接 $message = $attach['image_url'] && FALSE !== strpos($message, $attach['image_url']) ? str_replace($attach['image_url'], $url, $message) : $message; } } return $message; } function comment_filter($val) { unset($val['userip']); return $val; } function comment_highlight_keyword($str, $k) { $r = str_ireplace($k, '' . $k . '', $str); return $r; } // //
function comment_message_format(&$s) { if (xn_strlen($s) < 100) return; $s = preg_replace('#.*?
#is', '', $s); $s = str_ireplace(array('
', '
', '
', '

', '', '', '', '' . ''), "\r\n", $s); $s = str_ireplace(array(' '), " ", $s); $s = strip_tags($s); $s = preg_replace('#[\r\n]+#', "\n", $s); $s = xn_substr(trim($s), 0, 100); $s = str_replace("\n", '
', $s); } // 对内容进行引用 function comment_quote($quotepid) { $quotepost = comment_read($quotepid); if (empty($quotepost)) return ''; $uid = $quotepost['uid']; $s = $quotepost['message']; $s = comment_brief($s, 100); $userhref = url('user-' . $uid); $user = user_read_cache($uid); $r = '
' . $user['username'] . ' ' . $s . '
'; return $r; } // 获取内容的简介 0: html, 1: txt; 2: markdown; 3: ubb function comment_brief($s, $len = 100) { $s = strip_tags($s); $s = htmlspecialchars($s); $more = xn_strlen($s) > $len ? ' ... ' : ''; $s = xn_substr($s, 0, $len) . $more; return $s; } ?>Accessibility Issue: Multiple Links on Same Line in Flutter RichText - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Accessibility Issue: Multiple Links on Same Line in Flutter RichText - Stack Overflow

programmeradmin6浏览0评论

Steps to reproduce

  1. Create a RichText widget with multiple TextSpan or WidgetSpan elements, each representing a clickable link.

  2. Wrap each link in a Semantics widget to ensure accessibility support.

  3. Add GestureDetector to handle onTap events for each link.

  4. Test using a screen reader (TalkBack on Android or VoiceOver on iOS).

    Code sample:

MergeSemantics(
            child: RichText(
              text: TextSpan(
                style: const TextStyle(color: Colors.black, fontSize: 16.0),
                children: [
                  const TextSpan(
                    text:
                        'Android is a mobile operating system based on a modified version of the ',
                  ),
                  WidgetSpan(
                    child: Semantics(
                      label: 'Linux kernel',
                      button: true,
                      //link: true,
                      child: GestureDetector(
                        onTap: () {
                          print("Link 1 tapped!");
                        },
                        child: const Text(
                          'Linux kernel',
                          style: TextStyle(
                            color: Colors.blue,
                            decoration: TextDecoration.underline,
                          ),
                        ),
                      ),
                    ),
                  ),
                  const TextSpan(
                    text: ' and other ',
                  ),
                  WidgetSpan(
                    child: Semantics(
                      label: 'open-source',
                      button: true,
                      //link: true,
                      child: GestureDetector(
                        onTap: () {
                          print(" link 2 tapped!");
                        },
                        child: const Text(
                          'open-source',
                          style: TextStyle(
                            color: Colors.blue,
                            decoration: TextDecoration.underline,
                          ),
                        ),
                      ),
                    ),
                  ),
                  const TextSpan(
                    text: ' software.',
                  ),
                ],
              ),
            ),

Expected results

Whole content should be readable in a single tap and each link should be clickable.

Actual results

The screen reader only selects or announces the first link consistently.

The second link is often skipped or merged with surrounding text, making it inaccessible.

Steps to reproduce

  1. Create a RichText widget with multiple TextSpan or WidgetSpan elements, each representing a clickable link.

  2. Wrap each link in a Semantics widget to ensure accessibility support.

  3. Add GestureDetector to handle onTap events for each link.

  4. Test using a screen reader (TalkBack on Android or VoiceOver on iOS).

    Code sample:

MergeSemantics(
            child: RichText(
              text: TextSpan(
                style: const TextStyle(color: Colors.black, fontSize: 16.0),
                children: [
                  const TextSpan(
                    text:
                        'Android is a mobile operating system based on a modified version of the ',
                  ),
                  WidgetSpan(
                    child: Semantics(
                      label: 'Linux kernel',
                      button: true,
                      //link: true,
                      child: GestureDetector(
                        onTap: () {
                          print("Link 1 tapped!");
                        },
                        child: const Text(
                          'Linux kernel',
                          style: TextStyle(
                            color: Colors.blue,
                            decoration: TextDecoration.underline,
                          ),
                        ),
                      ),
                    ),
                  ),
                  const TextSpan(
                    text: ' and other ',
                  ),
                  WidgetSpan(
                    child: Semantics(
                      label: 'open-source',
                      button: true,
                      //link: true,
                      child: GestureDetector(
                        onTap: () {
                          print(" link 2 tapped!");
                        },
                        child: const Text(
                          'open-source',
                          style: TextStyle(
                            color: Colors.blue,
                            decoration: TextDecoration.underline,
                          ),
                        ),
                      ),
                    ),
                  ),
                  const TextSpan(
                    text: ' software.',
                  ),
                ],
              ),
            ),

Expected results

Whole content should be readable in a single tap and each link should be clickable.

Actual results

The screen reader only selects or announces the first link consistently.

The second link is often skipped or merged with surrounding text, making it inaccessible.

Share Improve this question edited Nov 19, 2024 at 12:10 Nishore kumar asked Nov 19, 2024 at 8:23 Nishore kumarNishore kumar 12 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Try using recognizer in TextSpan instead of using WidgetSpan and GestureDetector

MergeSemantics(
        child: RichText(
      text: TextSpan(
        style: const TextStyle(color: Colors.black, fontSize: 16.0),
        children: [
          const TextSpan(
            text:
                'Android is a mobile operating system based on a modified version of the ',
          ),
          TextSpan(
              text: 'Linux kernel',
              recognizer: TapGestureRecognizer()
                ..onTap = () {
                  print("Link 1 tapped!");
                }),
          const TextSpan(
            text: ' and other ',
          ),
          TextSpan(
              text: 'open-source',
              recognizer: TapGestureRecognizer()
                ..onTap = () {
                  print(" link 2 tapped!");
                }),
          const TextSpan(
            text: ' software.',
          ),
        ],
      ),
    ));
  }
发布评论

评论列表(0)

  1. 暂无评论