2024年Android最全Android-高级-UI-进阶之路-(七)-SVG-基础使用-+-绘制中国地图(1),头条面试题库

最后,面试前该准备哪些资源复习?

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一下我面试期间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)

《Android开发七大模块核心知识笔记》

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

《960全网最全Android开发笔记》

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

《379页Android开发面试宝典》

历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

需要注意的是,这里的文件是对应 Vector 中 path 标签的,这里动画效果是动态改变 path 标签的 trimPathStart 属性值,从 0 ~ 1 。

  1. 定义 animated-vector 进行关联
<?xml version="1.0" encoding="utf-8"?>



在上述代码中,drawable 代表关联的 vector 图像,target 代表将 path name 和动画进行关联

  1. 代码中进行设置

class SVGDemo1Activity : AppCompatActivity() {

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_svg)
startAnimatabe()
}

private fun startAnimatabe() {
val animatedVectorDrawable = AnimatedVectorDrawableCompat.create(this, R.drawable.line_animated_vector)
iv.setImageDrawable(animatedVectorDrawable)
val animatable = iv.drawable as Animatable
animatable.start()
}
}

实战

输入搜索动画

  1. 利用在线绘制 SVG 图标网站 制作搜索图标

可以自己随意捣鼓绘制,绘制好了之后点击视图->源代码,将 SVG 代码复制出来保存成 search_svg.xml

  1. 在线转换 svg2vector

点击空白或者直接将 SVG 拖拽指定区域进行转换

  1. 将转换好的 Android 格式的 vector 导入 AS

  1. 开始制作动画关联

//1.在 /res/aniamator 文件夹下 定义动画

<?xml version="1.0" encoding="utf-8"?>

<objectAnimator xmlns:android=“http://schemas.android.com/apk/res/android”
android:propertyName=“trimPathStart”
android:valueFrom=“1”
android:valueTo=“0”
android:duration=“2000”

//2. 在/res/drawable/ 定义 vector

<?xml version="1.0" encoding="utf-8"?>




//3. 在/res/drawable/ 关联动画和 vector

<?xml version="1.0" encoding="utf-8"?>



  1. 效果

警车灯闪烁

今日头条下拉刷新动画

来一个复杂组合动画,请看下面效果图:

  1. 准备 vector 数据




  1. 定义顺时针执行动画并做 pathData 变换

这里拿其中一个位置变化来举例说明:

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android=“http://schemas.android.com/apk/res/android”

android:ordering=“sequentially”>//按顺序执行

//依次执行 pathData 位置变换

<objectAnimator

android:duration=“600”
android:interpolator=“@android:interpolator/decelerate_cubic”
android:propertyName=“pathData”
android:valueFrom="
M100,30
L180,30
M180,30
L180,90
M180,90
L100,90
M100,90
L100,30"
android:valueTo="
M100,120
L180,120
M180,120
L180,180
M180,180
L100,180
M100,180
L100,120"
android:valueType=“pathType” />
<objectAnimator

android:duration=“600”
android:interpolator=“@android:interpolator/decelerate_cubic”
android:propertyName=“pathData”
android:valueFrom="
M100,120
L180,120
M180,120
L180,180
M180,180
L100,180
M100,180
L100,120"
android:valueTo="
M20,120
L100,120
M100,120
L100,180
M100,180
L20,180
M20,180
L20,120"
android:valueType=“pathType” />
<objectAnimator

android:duration=“600”
android:interpolator=“@android:interpolator/decelerate_cubic”
android:propertyName=“pathData”
android:valueFrom="
M20,120
L100,120
M100,120
L100,180
M100,180
L20,180
M20,180
L20,120"
android:valueTo="
M20,30
L100,30
M100,30
L100,90
M100,90
L20,90
M20,90
L20,30"
android:valueType=“pathType” />

如果对标签中的定义还不了解的先去看下文章中 path 标签 中的说明。如果不理解标签意思,根本就看不懂。

  1. 进行关联
<?xml version="1.0" encoding="utf-8"?>

<animated-vector xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:drawable=“@drawable/ic_toutiao”

tools:targetApi=“lollipop”>

  1. 代码控制重复执行

class SVGDemo1Activity : AppCompatActivity() {

var reStartTT = @SuppressLint(“HandlerLeak”)
object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
startAnimatabe(R.drawable.line_animated_toutiao, true)
}
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_svg)

//水滴动画
startWaterDropAnimator.setOnClickListener {
startAnimatabe(R.drawable.line_animated_vector, false)
}
//搜索动画
startSearchAnimator.setOnClickListener {
startAnimatabe(R.drawable.line_animated_search, false)
}
//执行警车动画
startPoliceCarAnimator.setOnClickListener {
startAnimatabe(R.drawable.line_animated_car, false)
}
//执行头条动画
startTTAnimator.setOnClickListener {
startAnimatabe(R.drawable.line_animated_toutiao, true)
}
}

private fun startAnimatabe(lineAnimatedVector: Int, isRegister: Boolean): Animatable {
val animatedVectorDrawable = AnimatedVectorDrawableCompat.create(this, lineAnimatedVector)
iv.setImageDrawable(animatedVectorDrawable)
val animatable = iv.drawable as Animatable
animatable.start()
animatedVectorDrawable!!.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
super.onAnimationEnd(drawable)
if (!isRegister) return
animatedVectorDrawable.unregisterAnimationCallback(this)
//重新开始在 xml 设置 restart 无效暂时用 Handler 实现了。
reStartTT.sendEmptyMessage(0)

}
})
return animatable

}
}

绘制中国地图

该篇之前实现 SVG pathData 都是利用 ImageView 来实现,并不是所有的场合都适合上面的方式,比如我想要实现 pathData 区域点击,那么上面所讲的方式应该是不能实现,下面我们以一个实例来看怎么自定义 View 实现 PathData 和 pathData 区域点击事件。

下面我们利用 path 来绘制一个中国地图,先来看一个最终效果图,如下:

看起来是不是很炫,还不错,嘿嘿,下面我们就来看一下如何实现。

  1. 准备地图 SVG
  • 首先去下载地图数据

  • 选择下载免费的地图数据

  • 找到对应的国家点击下载 svg 数据

  • 选择对应的地图数据,我这里下载的是高质量的 SVG

  1. SVG to Vector xml

将下载好的 china.svg 格式的文件转为 vector 节点的 xml 数据 或者用 AS 自带转也行,看个人爱好。

转好之后放入 AS 中,如下所示

现在有了这些数据,我们就可以解析 xml path 节点,拿到 pathData 数据我们不就可以绘制 path 了嘛。下面就开始解析 xml ,解析的方法很多种,我们这里用 dom 解析。

  1. 开始解析 xml

解析 xml 有很多种方式,这里就直接使用 DOM 解析,pathData2Path 我这里直接用 Android SDK 提供的 android.support.v4.graphics#PathParser 由于源码中它被标注了 hide 属性 ,我们需要直接将它 copy 到我们自己项目中, 具体转化请看如下代码:

/**

  • 开始解析 xml
    */
    public fun dom2xml(stream: InputStream?): MutableList {
    mapDataLists.clear()
    //dom
    val newInstance = DocumentBuilderFactory.newInstance()
    val newDocumentBuilder = newInstance.newDocumentBuilder()
    //拿到 Docment 对象
    val document = newDocumentBuilder.parse(stream)
    //获取 xml 中属于 path 节点的所有信息
    val elementsByTagName = document.getElementsByTagName(PATH_TAG)

//定义四个点,确定整个 map 的范围
var left = -1f
var right = -1f
var top = -1f
var bottom = -1f
//开始遍历标签,拿到 path 数据组
for (pathData in 0 until elementsByTagName.length) {
val item = elementsByTagName.item(pathData) as Element
val name = item.getAttribute(“android:name”)
val fillColor = item.getAttribute(“android:fillColor”)
val strokeColor = item.getAttribute(“android:strokeColor”)
val strokeWidth = item.getAttribute(“android:strokeWidth”)
val pathData = item.getAttribute(“android:pathData”)
val path = PathParser.createPathFromPathData(pathData)
mapDataLists.add(MapData(name, fillColor, strokeColor, strokeWidth, path))
//获取控件的宽高
val rect = RectF()
//获取到每个省份的边界
path.computeBounds(rect, true)
//遍历取出每个path中的left取所有的最小值
left = if (left == -1f) rect.left else Math.min(left, rect.left)
//遍历取出每个path中的right取所有的最大值
right = if (right == -1f) rect.right else Math.max(right, rect.right)
//遍历取出每个path中的top取所有的最小值
top = if (top == -1f) rect.top else Math.min(top, rect.top)
//遍历取出每个path中的bottom取所有的最大值
bottom = if (bottom == -1f) rect.bottom else Math.max(bottom, rect.bottom)
}
//MAP 的矩形区域
MAP_RECTF = RectF(left, top, right, bottom)
return mapDataLists;
}
复制代码

  1. 进行控件测量适配横竖屏切换和宽高定义 wrap_content 模式

/**

  • 开始测量
    */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    //测量模式
    var widthMode = MeasureSpec.getMode(widthMeasureSpec)
    var heightMode = MeasureSpec.getMode(heightMeasureSpec)
    //测量大小
    widthSize = MeasureSpec.getSize(widthMeasureSpec)
    heightSize = MeasureSpec.getSize(heightMeasureSpec)

if (!MAP_RECTF.isEmpty && mMapRectHeight != 0f && mMapRectWidth != 0f) {
//显示比例

总结

作为一名从事Android的开发者,很多人最近都在和我吐槽Android是不是快要凉了?而在我看来这正是市场成熟的表现,所有的市场都是温水煮青蛙,永远会淘汰掉不愿意学习改变,安于现状的那批人,希望所有的人能在大浪淘沙中留下来,因为对于市场的逐渐成熟,平凡并不是我们唯一的答案!

资料.png
资料图.jpg

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

_RECTF.isEmpty && mMapRectHeight != 0f && mMapRectWidth != 0f) {
//显示比例

总结

作为一名从事Android的开发者,很多人最近都在和我吐槽Android是不是快要凉了?而在我看来这正是市场成熟的表现,所有的市场都是温水煮青蛙,永远会淘汰掉不愿意学习改变,安于现状的那批人,希望所有的人能在大浪淘沙中留下来,因为对于市场的逐渐成熟,平凡并不是我们唯一的答案!

[外链图片转存中…(img-7Zp6YTwA-1714827418848)]
[外链图片转存中…(img-VR7RL8a8-1714827418849)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值