Compose
Rows,Columns,Box
Row 和Column是用来设置子项的位置。在水平方向(horizontal)和竖直方向(vertical)设置有两个参数,分别是排列(Arrangement)和布局(Alignment)
-
Arrangement
-
Center
-
End
-
Start
-
SpaceAround (每个元素之间的距离相等为d,但最顶部的距离与最近一个元素的距离为d/2)
-
SpaceBetween (尽可能的增大两个元素之间的距离)
-
SpaceEvenly (每个元素之间的距离相等)
-
-
Alignment
- Bottom(底部)
- Top (顶端)
- CenterVertically (居中对齐)
- BottomStart
//Row(horizontalArrangement =... ,
verticalAlignment=...){
...
}
//Column(verticalArrangement=... ,
horizontalAlignment=...){
...
}
Modifiers
Modifier 是一种修饰符
- 大小
- fillMaxSize(0.xf) 与父元素大小相等
- fillMaxWidth(0.xf)
- fillMaxHeight(0.xf)
- width(x.dp) 直接定义大小
- height(x.dp)
- requiredWidth 强制设定大小,不考虑父元素的限制
- 背景颜色
- background (Color. x)
- 边距
- padding(x.dp)
- offset(x.dp,x.dp)
- Spacer(modifier=Modifier.height(x.dp))
- border
- 特效
- clickable 点击
- scrollable 滚动
- draggable 拖拉
// Eg1
Column(modifier= Modifier.background(Color.Green) //设置背景(颜色)
.padding(15.dp) //设置内边距
)
//Eg2
Text("hello",modifier=Modifier.offset(50.dp,20.dp))
Spacer(modifier=Modifier.height(50.dp))
Text("world")
Image
- painterResource(id=R.drawable.x) 引入图片
- card(){} 卡片布局
- Image(){} 图片布局
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val painter = painterResource(id = R.drawable.pic1)
val description="我喜欢哆啦A梦"
val title="哆啦A梦"
Box(modifier = Modifier
.fillMaxSize(0.5f)
.padding(16.dp)){
ImageCard( //调用函数
painter = painter,
contentDescription = description,
title = title
)
}
}
}
}
@Composable
fun ImageCard(
painter: Painter,
contentDescription: String,
title: String,
modifier:Modifier=Modifier
) {
Card(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(15.dp), //形状
elevation = 5.dp
) {
Box(modifier = Modifier.height(200.dp)) {
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop
)
Box(modifier = Modifier
.fillMaxSize()
.background(
Brush.verticalGradient( // 黑色透明背景
colors = listOf(
Color.Transparent,
Color.Black
),
startY=300f
)
)
)
Box(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
contentAlignment = Alignment.BottomStart
) {
Text(title, style = TextStyle(color = Color.White, fontSize = 16.sp))
}
}
}
}
- 图片拖拽
@Preview(name = "studyImage")
@Composable
fun StudyImageView() {
val draggerOffset:MutableState<Float> = remember{ mutableStateOf(0f) }
val imageBitmap: ImageBitmap = ImageBitmap.imageResource(R.drawable.pic4)
Image(
bitmap = imageBitmap,
contentScale = ContentScale.FillBounds,
contentDescription ="Star",
modifier = Modifier.ImageModifier(draggerOffset)
)
}
private fun Modifier.ImageModifier(draggerOffset: MutableState<Float>):Modifier =
composed { Modifier
.height(260.dp)
.width(200.dp)
.padding(horizontal = 30.dp, vertical = 30.dp)
.clip(
RectangleShape
)
.rotate(10f)
.draggable(state = DraggableState(onDelta = {
draggerOffset.value = +it
Log.e("ondelta", "StudyImageView: " + draggerOffset.value)
}), orientation = Orientation.Horizontal)
.offset(x = draggerOffset.value.dp)
}
Styling Text
设置文字样式
Text(
text="...", //文本内容
color=Color.x, // 文字颜色
fontSize=x.sp //字号
fontStyle=FontStyle.Italic ,//斜体
fontWeight=FontWeight.Bold ,//粗体 FontWeight.thin 细 , FontWeight(0~1000)值越大,字体越粗
textAlign=TextAlign.Center ,//居中对齐
letterSpacing = TextUnit.Unspecified ,// 字间距 自定义间距 =x.sp
textDecoration = TextDecoration.None ,// 文本装饰 下划线 .underline 删除线.LineThrough
lineHeight = x.sp ,//行高
overflow = TextOverflow.Clip ,//文本溢出截断 .Ellipsis// 省略号表示
maxline=x //最大显示行数
softWrap = true //换行 =false 不换行
modifier = Modifier.border( //边框
border = BorderStroke(
width = 3.dp,
color = Color(0xFF999999),
),
shape = RoundedCornerShape(20f, 60f, 20f, 160f),
),
)
自带字体
溢出的文本
TextOverflow.Clip不指定宽高或最大行数时没有效果
TextOverflow.Ellipsis 配合 maxLines: Int 最大行数使用
软换行
包含多种样式
buildAnnotatedString{…}
- 字符级别
spanStyle
Text(
buildAnnotatedString {
withStyle(style = SpanStyle(color = Color.Blue)) {
append("H")
}
append("ello ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
append("W")
}
append("orld")
}
)
- 段落级别
ParagraphStyle
@Composable
fun ParagraphStyle() {
Text(
buildAnnotatedString {
withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
withStyle(style = SpanStyle(color = Color.Blue)) {
append("Hello\n")
}
withStyle(
style = SpanStyle(
fontWeight = FontWeight.Bold,
color = Color.Red
)
) {
append("World\n")
}
append("Compose")
}
}
)
}
用户互动
- 选择文字 SelectionContainer{ }
@Composable
fun PartiallySelectableText() {
SelectionContainer {
Column {
Text("This text is selectable")
Text("This one too")
Text("This one as well")
DisableSelection { // 不可以选择的部分
Text("But not this one")
Text("Neither this one")
}
Text("But again, you can select this one")
Text("And this one too")
}
}
}
State
- 随机变换颜色的盒子
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("hello")
ColorBox(
Modifier.fillMaxSize()
)
}
}
}
@Composable
fun ColorBox(modifier: Modifier=Modifier
){
val color= remember {
mutableStateOf(Color.Yellow)
}
Box(modifier = Modifier
.background(Color.Red)
.clickable {
color.value = Color(
Random.nextFloat(),
Random.nextFloat(),
Random.nextFloat(),
alpha = 1f
)
}
)
}
- 通过手势拖动盒子
@Preview
@Composable
fun TransformGestureDemo() {
var boxSize = 100.dp
var offset by remember { mutableStateOf(Offset.Zero) }
var ratationAngle by remember { mutableStateOf(0f) }
var scale by remember { mutableStateOf(1f) }
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Box(Modifier
.size(boxSize)
.rotate(ratationAngle) // 需要注意offset与rotate的调用先后顺序
.scale(scale)
.offset {
IntOffset(offset.x.roundToInt(), offset.y.roundToInt())
}
.background(Color.Green)
.pointerInput(Unit) {
detectTransformGestures(
panZoomLock = true, // 平移或放大时是否可以旋转
onGesture = { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->
offset += pan
scale *= zoom
ratationAngle += rotation
}
)
}
)
}
}
Textfield, Button,Sankerbars
- Textfield, Button
setContent {
val scaffoldState = rememberScaffoldState()
var textFieldState by remember {
mutableStateOf(" ")
}
val scope= rememberCoroutineScope()
Scaffold(modifier = Modifier.fillMaxSize(),
scaffoldState = scaffoldState
) {
Column(horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 30.dp)
) {
TextField(value = textFieldState,
onValueChange ={textFieldState=it},
label = {Text("Enter Your Name")} ,
singleLine =true,
modifier = Modifier.height(50.dp).fillMaxWidth(0.8f) )
Spacer(modifier = Modifier.height(16.dp))
Button( onClick={
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Hello $textFieldState")
}
}){
Text("pls greet me")
}
}
}
}
//Botton
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column(
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
ButtonDemo()
}
}
}
}
@Composable
fun ButtonDemo() {
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "Clicked on Button", Toast.LENGTH_SHORT).show()
})
{
Text("Standard")
}
Button(
onClick = {
Toast.makeText(context, "Clicked on Button", Toast.LENGTH_SHORT).show()
},
enabled = false
) {
Text("Disabled")
}
TextButton(onClick = {
Toast.makeText(context, "Clicked on Text Button", Toast.LENGTH_SHORT).show()
}) {
Text(" Text ")
}
OutlinedButton(onClick = {
Toast.makeText(context, "Clicked on Out Lined Button", Toast.LENGTH_SHORT).show()
}) {
Text("Outlined")
}
IconButton(onClick = {
Toast.makeText(context, "Clicked on Icon Button", Toast.LENGTH_SHORT).show()
}) {
Icon(
Icons.Filled.Refresh,
contentDescription = "Refresh Button",
tint = Color.DarkGray,
modifier = Modifier.size(80.dp)
)
}
}
Button(onClick = {
Toast.makeText(context, "Clicked on Button", Toast.LENGTH_SHORT).show()
},
contentPadding = PaddingValues(16.dp),
border = BorderStroke(10.dp, Color.Black),
colors = ButtonDefaults.textButtonColors(
backgroundColor = Color.DarkGray,
contentColor = Color.White
)
) {
Text("Add To Cart",
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(5.dp)
)
}
Button(onClick = {
Toast.makeText(context, "Clicked on Button", Toast.LENGTH_SHORT).show()
},
shape = CircleShape,//shape = CutCornerShape(10.dp),
contentPadding = PaddingValues(16.dp),
border = BorderStroke(10.dp, Color.Black),
colors = ButtonDefaults.textButtonColors(
backgroundColor = Color.DarkGray,
contentColor = Color.White
)
) {
Text("Add To Cart",
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(5.dp)
)
}
- List
LazyColumn {
itemsIndexed(
listOf("This","is","Jetpack","Compose")
){ index, string ->
Text(
text =string,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 24.dp)
)
}
}
sideEffect
- 点击按钮,数字加1
setContent {
val scaffoldState= rememberScaffoldState()
val scope= rememberCoroutineScope()
Scaffold(scaffoldState=scaffoldState) {
var counter by remember {
mutableStateOf(0)
}
if(counter %5==0 && counter>0){
LaunchedEffect(key1 = scaffoldState.snackbarHostState){
scaffoldState.snackbarHostState.showSnackbar("hello")
}
}
Button(onClick = {counter++}) {
Text("Click me: $counter")
}
}
}
setContent {
val scaffoldState= rememberScaffoldState()
val scope= rememberCoroutineScope()
Scaffold(scaffoldState=scaffoldState) {
var counter= produceState(initialValue =0 ){
delay(3000L)
value=4 //点击按钮后,直接跳转至4
}
if(counter.value %5==0 && counter.value>0){
LaunchedEffect(key1 = scaffoldState.snackbarHostState){
scaffoldState.snackbarHostState.showSnackbar("hello")
}
}
Button(onClick = {}) {
Text("Click me: ${counter.value}")
}
}
}
- 变大的盒子
//点击按钮自动增大
setContent {
var sizeState by remember {
mutableStateOf(200.dp)
}
val size by animateDpAsState(
targetValue = sizeState,
tween( //增大的较为平缓
durationMillis = 3000,
delayMillis = 300,
easing = LinearOutSlowInEasing
)
/*
spring( //增大的过程中有震荡
Spring.DampingRatioHighBouncy
)
keyframes { //增大的速度不同
durationMillis=5000
sizeState at 0 with LinearEasing
sizeState * 1.5f at 1000 with FastOutLinearInEasing
sizeState * 2f at 5000
}
*/
)
Box(modifier = Modifier
.size(size)
.background(Color.Red),
contentAlignment = Alignment.Center
){
Button(onClick = {
sizeState+=50.dp
}) {
Text("Increase size")
}
}
}
//从红渐变到绿再从绿变红
setContent {
var sizeState by remember {
mutableStateOf(200.dp)
}
val size by animateDpAsState(
targetValue = sizeState,
tween(
durationMillis = 1000
)
)
val infiniteTransition= rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
initialValue = Color.Red,
targetValue = Color.Green,
animationSpec = infiniteRepeatable(
tween(durationMillis = 2000),
repeatMode = RepeatMode.Reverse
)
)
Box(modifier = Modifier
.size(size)
.background(color),
contentAlignment = Alignment.Center
){
Button(onClick = {
sizeState+=50.dp
}) {
Text("Increase size")
}
}
}
- Progressbar
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Box(modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
){
CircularProgressBar(percentage = 0.8f, number =100 )
}
}
}
}
@Composable
fun CircularProgressBar(
percentage: Float,
number: Int,
fontSize:TextUnit=28.sp,
radius: Dp =50.dp,
color:Color= Color.Green,
strokeWidth:Dp=8.dp,
animDuration: Int=1000,
animDelay: Int=0
) {
var animationPlayed by remember {
mutableStateOf(false)
}
val curPercentage = animateFloatAsState(
targetValue = if (animationPlayed) percentage else 0f,
animationSpec = tween(
durationMillis = animDuration,
delayMillis = animDelay
)
)
LaunchedEffect(key1 = true) {
animationPlayed = true
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.size(radius * 2f)
) {
Canvas(modifier = Modifier.size(radius*2f))
{
drawArc(
color=color,
-90f,
360*curPercentage.value,
useCenter=false,
style=Stroke(strokeWidth.toPx(),cap= StrokeCap.Round)
)
}
Text(
text=(curPercentage.value*number).toInt().toString(),
color = Color.Black,
fontSize=fontSize,
fontWeight = FontWeight.Bold
)
}
}
- 折现图绘制
@Preview
@Composable
fun MyLineView(){
Canvas(
modifier = Modifier
.padding(10.dp)
.width(200.dp)
.height(100.dp),
){
drawIntoCanvas {canvas->
val paint= Paint()
paint.color=Color(208,208,208)
paint.style= PaintingStyle.Stroke
paint.strokeWidth=3f
val paintFill=Paint()
paintFill.color=Color.Gray
paintFill.style= PaintingStyle.Stroke
paintFill.strokeWidth=3f
//1.绘制坐标轴
canvas.translate(0f,size.height)
canvas.scale(1f,-1f)
//2.绘制x轴
val pathY =Path()
pathY.moveTo(0f,0f)
pathY.relativeLineTo(0f,size.height)
canvas.drawPath(pathY,paint)
//2.绘制y轴
val pathX =Path()
pathX.moveTo(0f,0f)
pathX.relativeLineTo(size.width,0f)
canvas.drawPath(pathX,paint)
val dataList:MutableList<Offset> = mutableListOf(Offset(20f,60f),Offset(40f,30f),Offset(50f,34f),Offset(80f,54f),Offset(100f,34f),Offset(200f,134f),Offset(400f,154f),Offset(480f,134f))
val linePath=Path()
paint.color=Color.Blue
val colors:MutableList<Color> = mutableListOf(Color.Red,Color.Blue,Color.Green)
paint.shader= LinearGradientShader(Offset(0f,0f),Offset(size.width,0f),colors,null,TileMode.Clamp)
paint.isAntiAlias=true
//3.绘制折线填充
for (index in 0 until dataList.size){
linePath.lineTo(dataList[index].x,dataList[index].y)
}
linePath.lineTo(dataList[dataList.size-1].x,0f)
linePath.close()
//绘制填充
paintFill.style= PaintingStyle.Fill
paintFill.shader= LinearGradientShader(Offset(0f,size.height),Offset(0f,0f), arrayListOf(Color(59,157,254,161),Color(59,157,254,21)),null,TileMode.Clamp)
canvas.drawPath(linePath,paintFill)
//2绘制折线2
val line =Path()
for (index in 0 until dataList.size){
line.lineTo(dataList[index].x,dataList[index].y)
}
paint.style= PaintingStyle.Stroke
canvas.drawPath(line,paint)
/*
//3绘制圆圈
paint.style= PaintingStyle.Fill
for (index in 0 until dataList.size){
canvas.drawCircle(Offset(dataList[index].x,dataList[index].y),6f,paint)
}
canvas.drawImage(image = bitmap, Offset(100f,100f),paint)
*/
}
}
}