Flutter Agora SDK Rounded Video SurfaceView - flutter

Does anyone know how to round the video corners in a video call? The container that I place them in has a border radius, but when the video starts it always shows a square container.
My video render code is below:
#override
Widget build(BuildContext context) {
return Stack(
children: [
_localSwitchRender == true
? rtc_local_view.SurfaceView()
: rtc_remote_view.SurfaceView(uid: widget.remoteUid.first),
Align(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: GestureDetector(
onTap: _switchRender,
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 42, 0, 0),
child: Stack(
children: [
Column(
children: [
const SizedBox(
height: 20
),
Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
color: Color(0x66333333),
),
width: 158,
height: 220,
foregroundDecoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
child: _localSwitchRender
? rtc_remote_view.SurfaceView(
uid: widget.remoteUid.first,
renderMode: VideoRenderMode.FILL,
)
: rtc_local_view.SurfaceView(
renderMode: VideoRenderMode.Hidden,
zOrderMediaOverlay: true,
),
),
],
),
],
),
),
),
),
),
],
);
}
}
Any help is greatly appreciated!

Place your widget inside ClipRRect:
ClipRRect(
borderRadius: BorderRadius.circular(10)
child: // your widget
)

Thanks Xoltwan! That worked:
ClipRRect(
borderRadius: BorderRadius.circular(10)
child: // your widget
)

Related

Making a scrollable page in Flutter

so I'm trying to make a registration page with multi fields for name and password and email etc.
my problem is that i couldn't make the page scrollable, can please help me with fixing that
I just want the page to be scrollable
Here is my Code :
class InstRegisterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0x47705C53), Color(0x9E36251D)],
stops: [0.1, 0.9],
begin: Alignment.topRight,
end: Alignment.bottomLeft,
),
),
child: Column(
children: [
Container(
child: wLogo(),
),
SizedBox(
height: 75,
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Color(0xFFF7F6F5),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(26),
topRight: Radius.circular(26)),
),
child: Column(
children: [
SizedBox(
height: 15,
),
CSfield('Particpent Name',''),
CSfieldEmail('Email',''),
CSfield('Password',''),
CSPasswordFiled('Phone Number',''),
CSButton(),
],
),
),
)
],
),
//child: InstHomePageWidgets(),
),
),
);
}
}
You can wrap your Column with a SingleChildScrollView to make it scrollable.
SingleChildScrollView(
child: Column(
children: [...]
),
)
You can check the page here to see all the scrollable widgets.
Also if the keyboard is pushes content up you can check this page

Ripple does not cover text

I figured I can draw ripple over an image by enclosing the image in Ink(decoration: BoxDecoration(image: ...)), but how can I do the same for Text?
This is supposed to be a card with an image on top and a title and some other information at the bottom:
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final post = _postModel.post;
return Material(
color: theme.colorScheme.background,
child: InkWell(
onTap: () {},
splashColor: Colors.red,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (post.imageUri != null)
// This image IS covered by the ripple (what I need)
AspectRatio(
aspectRatio: 5 / 3,
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
image: DecorationImage(
image: NetworkImage('https://picsum.photos/700'),
fit: BoxFit.cover,
),
),
),
),
// This must be underneath the ripple, but isn't.
Text(post.title, style: theme.textTheme.headline5),
Container(
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 5),
color: Colors.transparent,
height: 60,
child: Row(
children: <Widget>[
// This is also covered by the ripple
Ink(
height: 35,
width: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('https://picsum.photos/100'),
),
),
),
SizedBox(width: 5),
// This must be underneath the ripple but isn't
Ink(
// decoration: Decoration,
child: Text(
post.author,
style: theme.textTheme.caption,
),
),
Spacer(),
],
),
),
],
),
),
),
);
}
When I press, the ripple covers both images as expected, however, I can't figure out how to make the ripple cover the text widgets as well. I tried wrapping the text in an Ink widget (the last one), but it doesn't work - the text is still displayed over the ripple.
Unpressed:
Pressed (the text is visible):

How can I use carousel with hero in flutter?

I am trying to make a animation show bookmark. Just like the example on this website.The orignial example is too complicated. So I put part of code from the example of flutter doc. To learn the easiest animation. I have put same tag in both hero,but still error.
Please help me out.Thanks!
Sorry my english is poor.
Center(
child: FutureBuilder(
future: fetchData('querySdiList'),
builder: (context, qS) {
if (qS.hasData) {
return CarouselSlider.builder(
itemCount: qS.data.length,
itemBuilder: (BuildContext context, int itemIndex, int i) {
final list = qS.data[itemIndex];
sdiId = list['sdiId'];
print('carousel:' + sdiId.toString());
return Center(
child: SizedBox(
width: 300,
child: Hero(
tag: sdiId.toString(),
child: Material(
child: InkWell(
onTap: () {
// Navigator.pushNamed(context, '/BookMarkPage');
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
print('Hero:' + sdiId.toString());
return Container(
// Set background to blue to emphasize that it's a new route.
color: Colors.lightBlueAccent,
padding: const EdgeInsets.all(16.0),
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
child: Hero(
tag: sdiId.toString(),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {},
child: Image.network(
_image[0],
fit: BoxFit.contain,
),
),
),
),
));
}));
},
child: Container(
height:
MediaQuery.of(context).size.height / 2,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 10,
)
],
),
margin: EdgeInsets.all(5.0),
child: Stack(
alignment: Alignment.bottomLeft,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(15)),
child: Container(
height: MediaQuery.of(context)
.size
.height /
2,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_image[
Random().nextInt(
_image.length)])),
),
),
),
Container(
height: MediaQuery.of(context)
.size
.height,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(15)),
color: Colors.white,
gradient: LinearGradient(
begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomLeft,
colors: [
Colors.transparent,
Colors.black,
],
stops: [0.0, .85],
),
),
),
Container(
padding: EdgeInsets.all(10),
child: RichText(
text: TextSpan(
text: '${list['sdiName']}',
style: TextStyle(
fontSize: 50,
color: Colors.white),
),
),
height: MediaQuery.of(context)
.size
.height /
8,
),
],
),
),
),
))));
},
options: CarouselOptions(
aspectRatio: 2,
autoPlay: true,
enlargeCenterPage: true,
height: MediaQuery.of(context).size.height,
),
);
} else if (qS.hasError) {
return qS.error;
}
return CircularProgressIndicator();
},
),
),
error
There are multiple heroes that share the same tag within a subtree.
You are creating multiple widgets with the carouselBuilder and each one of them is getting the same tag, you cant do that, the tag is what tells the Hero widget where it should animate to.
The problem seem to be here
final list = qS.data[itemIndex];
sdiId = list['sdiId'];
try setting the hero tag as something like this
tag: qS.data[itemIndex]['sdiId']
this should give each of the heros the sdiId of the itemIndex preventing them from having the same one

How to make a container take up the height of the parent widget?

I have a card layout which looks like the following:
The code for it it as follows:
Card(
color: tap ? Colors.green : Colors.white,
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0),
child: Container(
child: Row(
children: [
**Container(
height: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),**
),
SizedBox(
width: 8.0,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
howManyThere() > 0 ? "${howManyThere()} x " : '',
style: addBTNHighlight,
),
Expanded(
child: Text(
widget.menuItem.item_name,
overflow: TextOverflow.ellipsis,
style: tap ? TitleWhite18Bold : Title18bold,
),
),
],
),
Container(
child: Text(
widget.menuItem.description,
//overflow: TextOverflow.ellipsis,
style: tap ? SubTitleWhite13 : SubTitle13,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
"£" + num.parse(widget.menuItem.price).toStringAsFixed(2),
style: tap ? priceHighlightSelected : priceHighlight,
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 6.0),
decoration: BoxDecoration(),
child: Text("ADD", style: tap ? priceHighlightWhite : addBTNHighlight)),
],
),
],
),
),
)
As you can see that I am almost there with my desired layout but with one small issue which can be seen in first and last item. Because of the given width and height of the image container, it leaves a gap on top and bottom.
What I would like to happen is that the width to stay the same but the height to be flexible and adjust with the height of the card itself. Is it possible?
When I remove the height attribute of the container with the image, I get a blank space of the image
UPDATE: I tried LayoutBuilder as well but without any Luck, it throws 'Incorrect use of ParentWidget' Exception. The code I used is as follows:
Row(
children: [
widget.menuItem.image.endsWith('/')
? Container()
: **LayoutBuilder(
builder: (context, constraints){
return Container(
width: 70.0,
height: constraints.minHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),
);
}**
),
Try this :
Column(
children: [
Expanded(
child: Container(
width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
image: DecorationImage(
image: NetworkImage(widget.menuItem.image),
fit: BoxFit.cover
),
),
),
),
],
),
The problem here is your description text which overflow your desired max height. You can try to constraint your Container with a height: 70.0 or you can add to your Text widget the property maxLines: 1.
LayoutBuilder only give you constraints that parent pass to child, which is something like 100 < width < 200, 300 < height < infinity. At this point the height of all texts on the right are not determined yet, so it is impossible to determined the height of image base on that.
One way to do this is to assign key to each list item, get item heights after everything is layout, the rebuild with those fixed height. This will become a two pass process and is less efficient.
The official solution to this is IntrinsicHeight, which conceptually do the same thing, but in a more optimized way.
Here is a minimum example:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: App(),
),
);
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
// This is where magic happened
child: IntrinsicHeight(
child: Row(
children: [
Container(
width: 100,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://cataas.com/cat'),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Text(
// just put some random text with dynamic height
'Text\n' * (Random().nextInt(4) + 4),
),
),
],
),
),
);
},
),
);
}
}
Remove height constraints, then
Try replacing fit: BoxFit.cover with BoxFit.fitHeight or BoxFit.fill.
In order to fill the image with card height you can give container required height and wrap the Image widget in AspectRatio widget with ratio 1. This will always helps image widget to fill parent card height. Have a look in below code.
Parent Widget
Container(
margin: EdgeInsets.only(bottom: 12),
height: 100,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 1,
child: _pictureWidget(widget.menuItem.image),
),
/// Replace `Container` with the needed widget
Expanded(child: Container()),
],
),
)
_pictureWidget
Widget _picture(String url) {
return _pictureWidget(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
child: Image.network(
url != null ? url : "",
fit: BoxFit.cover,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
),
);
}

Designing a Flutter button with image and text

If I just throw together an image and some text in a rounded-corner rectangle, the user will not know that they can "click here". But I don't have to bake my own solution. InkWell covers this scenario, complete with a nice shadow.
I am positioning
a custom clickable icon using the
InkWell
class, itself requiring to be inside an
Ink
instance.
import 'package:flutter/material.dart';
const boat_url = ('https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/'
'Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG/'
'182px-Segelboot_Bodensee_Mainau_%28Foto_Hilarmont%29.JPG');
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Image',
home: Scaffold(
backgroundColor: Colors.grey,
body: MyImage(),
)));
}
class MyImage extends StatelessWidget {
MyImage({Key key,});
#override
Widget build(BuildContext context) {
Size sz = MediaQuery.of(context).size * 0.4;
double border = 4;
return Stack(children: [
Positioned(
top: 100,
left: 100,
width: sz.width,
height: sz.height,
child: Material(
child: Ink(
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
new BoxShadow(
color: Colors.red,
blurRadius: 10.0,
offset: new Offset(30.0, 20.0),
),
],
border: Border.all(
color: Colors.blue,
width: border,
),
borderRadius: BorderRadius.circular(40),
),
child: InkWell(
onTap: (){/*..*/},
child: Column(
children: [
Container(
height: 4 * (sz.height - 2 * border) / 5,
alignment: Alignment.center,
child: Image.network(boat_url),
),
Container(
height: (sz.height - 2 * border) / 5,
child: FittedBox(
clipBehavior: Clip.antiAlias,
alignment: Alignment.centerLeft,
fit: BoxFit.fitHeight,
child: Text('A long descriptive sentence')),
)
],
)),
),
)),
]);
}
}
1- I'm not actually using Colors.white, and the Scaffold itself has
backgroundColor: Colors.grey. Where is the white background coming from?
2- When we talk of a "shadow", I'm expecting the shadow to be behind
the ink/inkwell object. Why does the shadow appear in front?
Related: 1
That white color is from the Material widget, to remove that you can use type param.
Material(
type: MaterialType.transparency,
child: Container(),
);
Here is code to achieve the custom button
Video link
Scaffold(
backgroundColor: Colors.blueGrey,
body: SafeArea(
child: Container(
decoration: BoxDecoration(
color: Colors.green.shade200,
border: Border.all(color: Colors.green),
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
blurRadius: 5,
spreadRadius: 2,
color: Colors.black26,
)
]),
margin: const EdgeInsets.all(20),
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {},
splashColor: Colors.black26,
child: IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Image.asset(
'assets/images/marked_tyre_base.png',
fit: BoxFit.cover,
width: 80,
height: 80,
),
const SizedBox(
height: 10,
),
Text(
'Tyre 1',
style: TextStyle(color: Colors.white),
)
]),
),
),
),
),
),
),
);
Screenshot:
Create a class, ImageTextButton:
class ImageTextButton extends StatelessWidget {
final VoidCallback onPressed;
final ImageProvider image;
final double imageHeight;
final double radius;
final Widget text;
ImageTextButton({
#required this.onPressed,
#required this.image,
this.imageHeight = 200,
this.radius = 28,
#required this.text,
});
#override
Widget build(BuildContext context) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: onPressed,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Ink.image(
image: image,
height: imageHeight,
fit: BoxFit.cover,
),
SizedBox(height: 6),
text,
SizedBox(height: 6),
],
),
),
);
}
}
Usage:
ImageTextButton(
onPressed: () {},
image: AssetImage('chocolate_image'),
text: Text('Chocolate'),
)