Flutter开源库和文章
flutter_excle Flutter插件生成Excle文件 - 库 - CSDN
Flutter3D玩的开心
flutter_time_axis时间轴插件 - GitHub
flutter_pickter_plugin支持图片和文件视频的等的选择 - 库 - GitHub
Flutter时间日期格式化等操作(一个月的最后一天日期,时间段内所有日期…)插件 - 库
WGS84与大地2000坐标转换(Java,C#,Dart)Flutter发布了支持库
当然还有很多在CSDN
B站教学链接
Android自定义绘制相关文章
Android自定义-艺术在于绘制
Android-自定义-曲线折线图表填充渐变,手势滑动,手势缩放等
Android自定义-任意区域可点击的折线图
Android自定义-手势缩放折线图
Android自定义-手势滑动缩放渐变填充曲线折线图表
Android-自定义可伸展的ViewGroup
Android自定义-曲线渐变填充
Jetpack-Compose
JetPack-Compose - 自定义绘制
当然还有很多在CSDN
IOS相关文章
SwiftUI学习笔记【基础UI
SwiftUI学习笔记-【列表】
SwiftUI学习笔记【path绘制】
SwiftUI学习笔记【Sqlite】
SwiftUI学习笔记【XML解析】
当然还有很多在CSDN
只要在编程的路上文章不会停下来...希望给你带来方便,你的点赞是我就是莫大的开心
自定义裁剪
和绘制
让应用的UI图破了天花板,而手势
和动画
的加入更让你的应用,赏心悦目、超凡脱俗。那我们的Compose是否可以呢?今天主要的内容是探究Compose在UI上所表现的能力。如果你对Flutter绘制和裁剪或者其他任何疑难杂症我想这个男人张风捷特烈一定能给你说的清清楚楚
,透透彻彻
。
手势
、动画
来创造花里胡哨的界面,当然这并不代表美,目的在于学习Compose的可创造性,这节会穿插自定义曲线的讲解,好像几乎都离不开曲线。先看看下面的效果?
UI界面不仅是简单的官方组件排布,好的UI更需要精心的自定义,和动态的交互性。上面图虽然不代表美,但包含了很多交互和动态效果,我们从组件的交互动态可能性作为出发点进行探讨。当然你觉得什么样的UI最难可以发表你的看法,有时间我定还你一个朗朗乾坤。技术交流群QQ裙730772561
。
Transform
或者RotationTransition
这样的容器部件进行包裹,且需要设置动画控制AnimationController等。那Compose我们如何来旋转和缩放组件呢?Modifier
不仅解决了参数过多可以统一配置问题,而且提供了极其强大的裁剪
、变换
、指针手势
、装饰
等方法,大大的提高了便捷性和创造性。旋转[Modifier.rotate(degrees: Float)]
、平移[Modifier.offset(x: Dp = 0.dp, y: Dp = 0.dp)]
、缩放[Modifier.scale(scale: Float)]
、等变换。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIlFcIoa-1616049802373)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/04e7f808b1bf4522b7e12281389df7db~tplv-k3u1fbpfcp-watermark.image)]
观察这部分动态特效
1、中间图片的旋转。
2、圆形图片外圆弧缩放。
3、背景的模糊和缩放。
4、运动的曲线。
Modifier.rotate
来设置,只需要在点击屏幕时候执行动画
继续性更新角度值即可。所以简单动画创建需要掌握一下。动画储值器
//进行动画过程数值储存器
val animatedDegree = remember {
Animatable(0f) }
执行动画
通过.animateTo(targetValue: T,animationSpec: AnimationSpec = defaultSpringSpec…)开始执行动画,可以设置动画目标值和动画规格速度等…
animatedOffset.animateTo(targetValue,animationSpec = spring(stiffness = StiffnessLow))
fun Modifier.pointerInput(key1: Any?, block: suspend PointerInputScope.() -> Unit)
:以处理修改后的元素区域内的指针输入。pointerInput可以调用PointerInputScope-awaitPointerEventScope
来安装一个指针输入处理程序,该处理程序可以使waitPointerEventScope-awaitPointerEvent接收
和使用指针输入事件
。 可以通过PointerInputScope.AwaitPointerEventScope
上的扩展功能定义为执行更高级别的手势检测。 我们通过awaitPointerEventScope获取屏幕点击坐标作为我们的角度。
@Compose
fun LoginPage(){
//1.进行动画过程数值储存器
val animatedDegree = remember {
Animatable(0f) }
Box() {
//底部模糊大背景
Image(
//获取模糊bitmap
bitmap = BitmapBlur.doBlur(getBitmap(resource =R.drawable.head_god).asAndroidBitmap(),
animatedRound.value.toInt()+20,false).asImageBitmap(),
contentDescription = "",
contentScale = ContentScale.FillHeight,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.scale(animatedScale.value, animatedScale.value),
)
//圆形图片和圆形弧圈
Column(verticalArrangement = Arrangement.Center, modifier = Modifier.pointerInput(Unit) {
coroutineScope {
while (true) {
//2.通过awaitPointerEventScope来处理指针事件
val offset = awaitPointerEventScope {
//获取第一次按下的位置坐标
awaitFirstDown().position
}
//携程
launch {
//3.设置animated的目标值为按下的屏幕坐标系内的x值,且设置动画格式为比较平缓不生硬。开始执行动画。
animatedDegree.animateTo(
offset.x,
animationSpec = spring(stiffness = StiffnessLow)
)
}
}
}
}) {
Image( bitmap = getBitmap(R.drawable.head_god),
contentDescription = "w",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.height(80.dp)
.width(80.dp)
.background(color = Color(0XFF0DBEBF), shape = CircleShape)
.padding(3.dp)
.clip(
CircleShape
)
.shadow(elevation = 150.dp, clip = true)
.rotate(//4.设置角度为初始化到目标x的动画值跟新UI
animatedDegreen.value
)
)
}
}
缩放
和颜色
动画val animatedScale = remember { Animatable(1f) }
来创建缩数值储存器,通过点击时候执行动画去跟新图片大小颜色也是同样设置val animatedColor = remember { Animatable(Color(206, 199, 250, 121)) }
点击时候去设置目标缩放值和颜色执行.animalTo即可执行连续动画且向上去跟新储存状态再下发到跟新UI。圆形裁剪相关的看之前文章 Box(contentAlignment = Alignment.Center,
modifier = Modifier.padding(0.dp).clip(CicleImageShape())
.background(animatedColor.value)
.width((130 * animatedScale.value).dp)
.height((130 * animatedScale.value).dp)
) {
Image(
bitmap = getBitmap(R.drawable.head_god),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.height(80.dp)
.width(80.dp)
.background(color = Color(0XFF0DBEBF), shape = CircleShape)
.padding(3.dp)
.clip(
CircleShape
)
.shadow(elevation = 150.dp, clip = true)
.rotate(
animatedOffset.value
)
)
}
Bitmap和ImageBitmap可以相互转换:
Bitmap.asImageBitmap(): ImageBitmap
和fun ImageBitmap.asAndroidBitmap(): Bitmap
object BitmapBlur {
fun doBlur(sentBitmap: Bitmap, radiu: Int = 1, canReuseInBitmap: Boolean): Bitmap {
var radius: Int = radiu
val bitmap: Bitmap = if (canReuseInBitmap) {
sentBitmap
} else {
sentBitmap.copy(sentBitmap.config, true)
}
if (radius < 1) {
radius = 0
}
val w = bitmap.width
val h = bitmap.height
val pix = IntArray(w * h)
bitmap.getPixels(pix, 0, w, 0, 0, w, h)
val wm = w - 1
val hm = h - 1
val wh = w * h
val div = radius + radius + 1
val r = IntArray(wh)
val g = IntArray(wh)
val b = IntArray(wh)
var rsum: Int
var gsum: Int
var bsum: Int
var x: Int
var y: Int
var i: Int
var p: Int
var yp: Int
var yi: Int
var yw: Int
val vmin = IntArray(Math.max(w, h))
var divsum = div + 1 shr 1
divsum *= divsum
val dv = IntArray(256 * divsum)
i = 0
while (i < 256 * divsum) {
dv[i] = i / divsum
i++
}
yi = 0
yw = yi
val stack = Array(div) {
IntArray(
3
)
}
var stackpointer: Int
var stackstart: Int
var sir: IntArray
var rbs: Int
val r1 = radius + 1
var routsum: Int
var goutsum: Int
var boutsum: Int
var rinsum: Int
var ginsum: Int
var binsum: Int
y = 0
while (y < h) {
bsum = 0
gsum = bsum
rsum = gsum
boutsum = rsum
goutsum = boutsum
routsum = goutsum
binsum = routsum
ginsum = binsum
rinsum = ginsum
i = -radius
while (i <= radius) {
p = pix[yi + Math.min(wm, Math.max(i, 0))]
sir = stack[i + radius]
sir[0] = p and 0xff0000 shr 16
sir[1] = p and 0x00ff00 shr 8
sir[2] = p and 0x0000ff
rbs = r1 - Math.abs(i)
rsum += sir[0] * rbs
gsum += sir[1] * rbs
bsum += sir[2] * rbs
if (i > 0) {
rinsum += sir[0]
ginsum += sir[1]
binsum += sir[2]
} else {
routsum += sir[0]
goutsum += sir[1]
boutsum += sir[2]
}
i++
}
stackpointer = radius
x = 0
while (x < w) {
r[yi] = dv[rsum]
g[yi] = dv[gsum]
b[yi] = dv[bsum]
rsum -= routsum
gsum -= goutsum
bsum -= boutsum
stackstart = stackpointer - radius + div
sir = stack[stackstart % div]
routsum -= sir[0]
goutsum -= sir[1]
boutsum -= sir[2]
if (y == 0) {