Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
9d4e0e85
Commit
9d4e0e85
authored
Feb 25, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2142 from abarth/interactive_text
Add the ability to recognize gestures on text spans
parents
4ef20148
8e326d72
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
141 additions
and
10 deletions
+141
-10
text_painter.dart
packages/flutter/lib/src/painting/text_painter.dart
+48
-7
paragraph.dart
packages/flutter/lib/src/rendering/paragraph.dart
+13
-3
hyperlink_test.dart
packages/flutter/test/widget/hyperlink_test.dart
+80
-0
No files found.
packages/flutter/lib/src/painting/text_painter.dart
View file @
9d4e0e85
...
@@ -4,6 +4,8 @@
...
@@ -4,6 +4,8 @@
import
'dart:ui'
as
ui
show
Paragraph
,
ParagraphBuilder
,
ParagraphStyle
,
TextBox
;
import
'dart:ui'
as
ui
show
Paragraph
,
ParagraphBuilder
,
ParagraphStyle
,
TextBox
;
import
'package:flutter/gestures.dart'
;
import
'basic_types.dart'
;
import
'basic_types.dart'
;
import
'text_editing.dart'
;
import
'text_editing.dart'
;
import
'text_style.dart'
;
import
'text_style.dart'
;
...
@@ -26,7 +28,8 @@ class TextSpan {
...
@@ -26,7 +28,8 @@ class TextSpan {
const
TextSpan
({
const
TextSpan
({
this
.
style
,
this
.
style
,
this
.
text
,
this
.
text
,
this
.
children
this
.
children
,
this
.
recognizer
});
});
/// The style to apply to the text and the children.
/// The style to apply to the text and the children.
...
@@ -44,6 +47,9 @@ class TextSpan {
...
@@ -44,6 +47,9 @@ class TextSpan {
/// children.
/// children.
final
List
<
TextSpan
>
children
;
final
List
<
TextSpan
>
children
;
/// If non-null, will receive events that hit this text span.
final
GestureRecognizer
recognizer
;
void
build
(
ui
.
ParagraphBuilder
builder
)
{
void
build
(
ui
.
ParagraphBuilder
builder
)
{
final
bool
hasStyle
=
style
!=
null
;
final
bool
hasStyle
=
style
!=
null
;
if
(
hasStyle
)
if
(
hasStyle
)
...
@@ -60,13 +66,47 @@ class TextSpan {
...
@@ -60,13 +66,47 @@ class TextSpan {
builder
.
pop
();
builder
.
pop
();
}
}
void
writePlainText
(
StringBuffer
result
)
{
bool
visitTextSpan
(
bool
visitor
(
TextSpan
span
))
{
if
(
text
!=
null
)
if
(
text
!=
null
)
{
result
.
write
(
text
);
if
(!
visitor
(
this
))
return
false
;
}
if
(
children
!=
null
)
{
if
(
children
!=
null
)
{
for
(
TextSpan
child
in
children
)
for
(
TextSpan
child
in
children
)
{
child
.
writePlainText
(
result
);
if
(!
child
.
visitTextSpan
(
visitor
))
return
false
;
}
}
}
return
true
;
}
TextSpan
getSpanForPosition
(
TextPosition
position
)
{
TextAffinity
affinity
=
position
.
affinity
;
int
targetOffset
=
position
.
offset
;
int
offset
=
0
;
TextSpan
result
;
visitTextSpan
((
TextSpan
span
)
{
assert
(
result
==
null
);
int
endOffset
=
offset
+
span
.
text
.
length
;
if
(
targetOffset
==
offset
&&
affinity
==
TextAffinity
.
downstream
||
targetOffset
>
offset
&&
targetOffset
<
endOffset
||
targetOffset
==
endOffset
&&
affinity
==
TextAffinity
.
upstream
)
{
result
=
span
;
return
false
;
}
offset
=
endOffset
;
return
true
;
});
return
result
;
}
String
toPlainText
()
{
StringBuffer
buffer
=
new
StringBuffer
();
visitTextSpan
((
TextSpan
span
)
{
buffer
.
write
(
span
.
text
);
return
true
;
});
return
buffer
.
toString
();
}
}
String
toString
([
String
prefix
=
''
])
{
String
toString
([
String
prefix
=
''
])
{
...
@@ -89,9 +129,10 @@ class TextSpan {
...
@@ -89,9 +129,10 @@ class TextSpan {
final
TextSpan
typedOther
=
other
;
final
TextSpan
typedOther
=
other
;
return
typedOther
.
text
==
text
return
typedOther
.
text
==
text
&&
typedOther
.
style
==
style
&&
typedOther
.
style
==
style
&&
typedOther
.
recognizer
==
recognizer
&&
_deepEquals
(
typedOther
.
children
,
children
);
&&
_deepEquals
(
typedOther
.
children
,
children
);
}
}
int
get
hashCode
=>
hashValues
(
style
,
text
,
hashList
(
children
));
int
get
hashCode
=>
hashValues
(
style
,
text
,
recognizer
,
hashList
(
children
));
}
}
/// An object that paints a [TextSpan] into a canvas.
/// An object that paints a [TextSpan] into a canvas.
...
...
packages/flutter/lib/src/rendering/paragraph.dart
View file @
9d4e0e85
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'package:flutter/gestures.dart'
;
import
'box.dart'
;
import
'box.dart'
;
import
'object.dart'
;
import
'object.dart'
;
import
'semantics.dart'
;
import
'semantics.dart'
;
...
@@ -81,6 +83,16 @@ class RenderParagraph extends RenderBox {
...
@@ -81,6 +83,16 @@ class RenderParagraph extends RenderBox {
bool
hitTestSelf
(
Point
position
)
=>
true
;
bool
hitTestSelf
(
Point
position
)
=>
true
;
void
handleEvent
(
PointerEvent
event
,
BoxHitTestEntry
entry
)
{
if
(
event
is
!
PointerDownEvent
)
return
;
_layoutText
(
constraints
);
Offset
offset
=
entry
.
localPosition
.
toOffset
();
TextPosition
position
=
_textPainter
.
getPositionForOffset
(
offset
);
TextSpan
span
=
_textPainter
.
text
.
getSpanForPosition
(
position
);
span
?.
recognizer
?.
addPointer
(
event
);
}
void
performLayout
()
{
void
performLayout
()
{
_layoutText
(
constraints
);
_layoutText
(
constraints
);
size
=
constraints
.
constrain
(
_textPainter
.
size
);
size
=
constraints
.
constrain
(
_textPainter
.
size
);
...
@@ -100,9 +112,7 @@ class RenderParagraph extends RenderBox {
...
@@ -100,9 +112,7 @@ class RenderParagraph extends RenderBox {
Iterable
<
SemanticAnnotator
>
getSemanticAnnotators
()
sync
*
{
Iterable
<
SemanticAnnotator
>
getSemanticAnnotators
()
sync
*
{
yield
(
SemanticsNode
node
)
{
yield
(
SemanticsNode
node
)
{
StringBuffer
buffer
=
new
StringBuffer
();
node
.
label
=
text
.
toPlainText
();
text
.
writePlainText
(
buffer
);
node
.
label
=
buffer
.
toString
();
};
};
}
}
...
...
packages/flutter/test/widget/hyperlink_test.dart
0 → 100644
View file @
9d4e0e85
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:test/test.dart'
;
void
main
(
)
{
test
(
'Can tap a hyperlink'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
bool
didTapLeft
=
false
;
TapGestureRecognizer
tapLeft
=
new
TapGestureRecognizer
(
router:
Gesturer
.
instance
.
pointerRouter
,
gestureArena:
Gesturer
.
instance
.
gestureArena
,
onTap:
()
{
didTapLeft
=
true
;
}
);
bool
didTapRight
=
false
;
TapGestureRecognizer
tapRight
=
new
TapGestureRecognizer
(
router:
Gesturer
.
instance
.
pointerRouter
,
gestureArena:
Gesturer
.
instance
.
gestureArena
,
onTap:
()
{
didTapRight
=
true
;
}
);
Key
textKey
=
new
Key
(
'text'
);
tester
.
pumpWidget
(
new
Center
(
child:
new
RichText
(
key:
textKey
,
text:
new
TextSpan
(
children:
<
TextSpan
>[
new
TextSpan
(
text:
'xxxxxxxx'
,
recognizer:
tapLeft
),
new
TextSpan
(
text:
'yyyyyyyy'
),
new
TextSpan
(
text:
'zzzzzzzzz'
,
recognizer:
tapRight
),
]
)
)
)
);
Element
element
=
tester
.
findElementByKey
(
textKey
);
RenderBox
box
=
element
.
renderObject
;
expect
(
didTapLeft
,
isFalse
);
expect
(
didTapRight
,
isFalse
);
tester
.
tapAt
(
box
.
localToGlobal
(
Point
.
origin
)
+
new
Offset
(
2.0
,
2.0
));
expect
(
didTapLeft
,
isTrue
);
expect
(
didTapRight
,
isFalse
);
didTapLeft
=
false
;
tester
.
tapAt
(
box
.
localToGlobal
(
Point
.
origin
)
+
new
Offset
(
30.0
,
2.0
));
expect
(
didTapLeft
,
isTrue
);
expect
(
didTapRight
,
isFalse
);
didTapLeft
=
false
;
tester
.
tapAt
(
box
.
localToGlobal
(
new
Point
(
box
.
size
.
width
,
0.0
))
+
new
Offset
(-
2.0
,
2.0
));
expect
(
didTapLeft
,
isFalse
);
expect
(
didTapRight
,
isTrue
);
});
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment