Like Whatsapp, how to make an input that extends to upwards as you type?
I would use a contenteditable
div that you simply put at the bottom and it will behave like expected
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background: #262626;
}
.tel {
margin: 20px auto 0;
width: 300px;
height: 500px;
background: #fff;
border-radius: 20px;
position: relative;
}
.tel .screen {
width: 280px;
height: 400px;
background: url("https://user-images.githubusercontent.com/15075759/28719144-86dc0f70-73b1-11e7-911d-60d70fcded21.png");
left: 50%;
position: absolute;
top: 50px;
transform: translate(-50%, 0);
}
.tel .screen .nav {
width: 100%;
position: absolute;
top: 0;
left: 0;
height: 50px;
background: #075E54;
}
.tel .screen #inp {
position: absolute;
left: 6px;
bottom: 6px;
width: 225px;
min-height: 37px;
border-radius: 50px;
border: none;
outline: none;
font-size: 14px;
padding: 2px 10px;
}
.tel .screen .voice {
position: absolute;
right: 6px;
bottom: 6px;
background: #00897B;
height: 37px;
width: 37px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.tel .speaker {
width: 50px;
height: 4px;
background: #a0a0a0;
position: absolute;
left: 50%;
transform: translate(-50%, 0);
top: 25px;
border-radius: 2px;
}
.tel .touch {
height: 30px;
width: 30px;
position: absolute;
left: 50%;
transform: translateX(-50%);
background: conic-gradient(#b3b3b3 0%, #a0a0a0 50%, #b3b3b3 50%, #a0a0a0 100%);
border-radius: 50%;
bottom: 10px;
}
i {
color: #fff;
font-size: 14px;
}
div.edit {
position: absolute;
bottom: 4px;
left: 5px;
right: 50px;
padding: 10px;
min-height: 40px;
background: #fff;
border-radius: 15px;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="tel">
<div class="speaker"></div>
<div class="screen">
<div class="nav"></div>
<div contenteditable="true" class="edit"></div>
<div class="voice">
<i class="material-icons">keyboard_voice</i>
</div>
</div>
<div class="touch"></div>
</div>
How to create a Rich Text Input like Telegram or WhatsApp chat page in Flutter?
I found a way to do this by creating a custom TextEditingController
, but reserved characters still exist and are just not visible:
import 'dart:ui';
import 'package:flutter/material.dart';
class RichTextFieldController extends TextEditingController {
late final Pattern pattern;
String pureText = '';
final Map<String, TextStyle> map = {
r'@.\w+': const TextStyle(color: Colors.blue),
r'#.\w+': const TextStyle(color: Colors.blue),
r'\*\*(.*?)\*\*': const TextStyle(fontWeight: FontWeight.bold),
r'__(.*?)__': const TextStyle(fontStyle: FontStyle.italic),
'~~(.*?)~~': const TextStyle(decoration: TextDecoration.lineThrough),
r'```(.*?)```': const TextStyle(
fontFamily: 'mono',
fontFeatures: [FontFeature.tabularFigures()],
)
};
RichTextFieldController() {
pattern = RegExp(map.keys.map((key) => key).join('|'), multiLine: true);
}
@override
set text(String newText) {
value = value.copyWith(
text: newText,
selection: TextSelection.collapsed(offset: newText.length),
composing: TextRange.empty,
);
}
@override
TextSpan buildTextSpan({
required context,
TextStyle? style,
required bool withComposing,
}) {
final List<InlineSpan> children = [];
text.splitMapJoin(
pattern,
onMatch: (Match match) {
String? formattedText;
String? textPattern;
final patterns = map.keys.toList();
if (RegExp(patterns[0]).hasMatch(match[0]!)) {
formattedText = match[0];
textPattern = patterns[0];
} else if (RegExp(patterns[1]).hasMatch(match[0]!)) {
formattedText = match[0];
textPattern = patterns[1];
} else if (RegExp(patterns[2]).hasMatch(match[0]!)) {
formattedText = match[0]!.replaceAll("**", "");
textPattern = patterns[2];
} else if (RegExp(patterns[3]).hasMatch(match[0]!)) {
formattedText = match[0]!.replaceAll("__", "");
textPattern = patterns[3];
} else if (RegExp(patterns[4]).hasMatch(match[0]!)) {
formattedText = match[0]!.replaceAll("~~", "");
textPattern = patterns[4];
} else if (RegExp(patterns[5]).hasMatch(match[0]!)) {
formattedText = match[0]!.replaceAll("```", "");
textPattern = patterns[5];
}
children.add(TextSpan(
text: formattedText,
style: style!.merge(map[textPattern!]),
));
return "";
},
onNonMatch: (String text) {
children.add(TextSpan(text: text, style: style));
return "";
},
);
return TextSpan(style: style, children: children);
}
}
how to show like chat box for the div/p tag top left/right corners
Use pseudoelements ::after and ::before.
.right {
position: relative;
background: aqua;
text-align: right;
min-width: 45%;
padding: 10px 15px;
border-radius: 6px;
border: 1px solid #ccc;
float: right;
right: 20px;
}
.right::before {
content: '';
position: absolute;
visibility: visible;
top: -1px;
right: -10px;
border: 10px solid transparent;
border-top: 10px solid #ccc;
}
.right::after {
content: '';
position: absolute;
visibility: visible;
top: 0px;
right: -8px;
border: 10px solid transparent;
border-top: 10px solid aqua;
clear: both;
}
<div class="right">
<span>thanks</span>
</div>
For example https://jsfiddle.net/2bekec10/
flutter - chat's input box keyboard pushing message-list upwards
This seems to work for me:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ScrollController _controller = ScrollController();
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays([]);
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
buildMessageList(),
buildInputArea(context),
],
),
),
);
}
Widget buildInputArea(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: TextField(),
),
RaisedButton(
onPressed: null,
child: Icon(Icons.send),
),
],
);
}
Widget buildMessageList() {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 50,
controller: _controller,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(10),
child: Container(
color: Colors.red,
height: 20,
child: Text(index.toString()),
),
);
},
),
);
}
}
I think the problem is that you are using fixed sizes for all widgets. In this case it is better to use Expanded
for the ListView
and removing the SingleChildScrollView
. That way the whole Column
won't scroll, but only the ListView
.
Related Topics
CSS Wrong Appearance of Border-Radius on a Nested Div
Restoring the Value of a Input Type=File After Failed Validation
Can Xhtml and HTML Class Attributes Value Start with a Number
How to Cut a Circular Part from an Image
How to Implement Curve Background in CSS
Floating Elements Are Outside of Containing Blocks
Flexbox Resize and Scrollable Overflow
Chrome: Automatic Shift of Web Elements
Use Fieldset Legend with Bootstrap
How to Center Div Vertically Inside of Absolutely Positioned Parent Div
Center Image in Div Horizontally
How to Vertically Align Something Inside a Span Tag
Put Icon Inside Input Element in a Form (Not as Background Image!)