Like Whatsapp, How to Make an Input That Extends to Upwards as You Type

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



Leave a reply



Submit