Android如何动态添加View并显示在指定位置。

Android如何动态添加View并显示在指定位置。

2023年7月15日发(作者:)

Android如何动态添加View并显⽰在指定位置。引⼦最近,在做产品的需求的时候,遇到 PM 要求在某个按钮上添加⼀个新⼿引导动画,引导⽤户去点击。作为 RD,我哗啦啦的就写好相关逻辑了。⾃测完成后,提测,PM Review 效果。看完后,PM 提了个问题,这个动画效果范围能不能再⼤⼀点?PM 解释到按钮本⾝⼤⼩不是很⼤,会导致引导效果不够明显,也会导致⽤户的点击欲望不够。我想了想,似乎很有道理啊,但是这个能做到吗?答案是当然可以呢。如果单纯从现在的布局上去将动画的尺⼨去扩⼤,得改变原本的布局。这个引导只出现⼏次,为了引导,⽽去改动原有的布局,个⼈觉得改动还是蛮⼤的。不值得!于是想⽤ clipChildren 属性来试着让 ⼦ view 突破⽗布局,但是这样同样会影响其他⼦ view,也不好去与按钮的中⼼进⾏定位。那还有没有其他尽可能不去改动原有布局就可以实现的⽅案呢?有的!准备知识相信⼤家都对下⾯这段代码会很熟悉:protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main);} 这段代码执⾏后,将 activity_main 这个布局添加到了 DecorView 。对于 activity 与 DecorView 之间的关系,⼤家可以看这篇⽂章:DecorView 是⼀个应⽤窗⼝的根容器,它本质上是⼀个 FrameLayout。DecorView 有唯⼀⼀个⼦ View,它是⼀个垂直 LinearLayout,包含两个⼦元素,⼀个是 TitleView( ActionBar 的容器),另⼀个是 ContentView(窗⼝内容的容器)也是⼀个FrameLayout(t),平常⽤的 setContentView 就是设置它的⼦ View 。后⾯我们就是在 ContentView 上做⽂章。另外,对于 FrameLayout,他的⼦ view 如果没有指定 Gravity 的话,那么就会堆积再左上⾓,谁是后⾯添加的谁在上⾯。其实使⽤也可以下⾯两个⽅法来决定放置的位置: public void setX(float x) { setTranslationX(x - mLeft); } public void setY(float y) { setTranslationY(y - mTop); } 可以发现这两个⽅法其实是都通过设置平移的偏移的量来实现的。这样我们就可以指定 View 所显⽰的位置的。那如何去获取 PM 需求中所要求的位置呢?如果这个按钮是 wrap_content 的,按钮的宽度是⽆法确定的?那就只能拿到按钮对应的 View 实例,通过该实例就可以获取到按钮的宽⾼。获取 view 的显⽰位置按钮的宽⾼知道后,结合前⾯介绍的两个设置显⽰位置⽅法,有些⼈应该已经猜到要怎么做了。如果能够知道按钮的显⽰位置,这时候只要调⽤这两个⽅法,就可以将动画 view 显⽰位置确定下来。那我要怎么去获取按钮的显⽰位置呢。下⾯就得介绍另⼀个⽅法呢。 public final boolean getLocalVisibleRect(Rect r) { final Point offset = mAttachInfo != null ? : new Point(); if (getGlobalVisibleRect(r, offset)) { (-offset.x, -offset.y); // make r local return true; } return false; } 在来看看 getGlobalVisibleRect 的实现, public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { int width = mRight - mLeft; int height = mBottom - mTop; if (width > 0 && height > 0) { (0, 0, width, height); if (globalOffset != null) { (-mScrollX, -mScrollY); } return mParent == null || ldVisibleRect(this, r, globalOffset); } return false; }

简单来说,就是 rect 是 View 的宽⾼和 View 的偏移量综合的结果,具体计算过程咱就不纠结了,下⾯说下每个数字代表的含义:其中对于 getLocalVisibleRect 来说: ⼤于0,表⽰左边已经处于不可见,否则是等于0; ⼤于0,表⽰上边已经处于不可见,否则是等于0; ⼩于 View 的宽度,表是处于不可见,否则是等于 View 的宽度; ⼩于 View 的⾼度,表是处于不可见,否则是等于 View 的⾼度;View 的可见⾼度 = - ;View 的可见宽度 = - ;对于 getGlobalVisibleRect 来说:就是其在屏幕当中的位置。具体可见下⾯的 gif 图相信⼤家在有了上述知识基础之后,就知道要怎么做了。下⼀步就是实战。实践⽬标:将⼀个 imageView 居中显⽰在⼀个 TextView 上⾯。步骤:1. 获取锚点 TextView 实例对象;2. 根据实例对象获取 ContentView;3. 根据 ContentView 和 TextView 的显⽰位置确定 TextView 在 ContentView 中的位置;4. 将 imageView 添加到 ContentView 上,根据位置调整位置。经过上⾯四步即可将⼀个 view 添加到任何⼀个位置呢。最终实现效果:

源码下⾯是具体实现代码,为了便于该逻辑的重复利⽤,我稍微进⾏了封装。采⽤的是 builder 模式,虽然我的变量⽐较少,但是真的当封装的功能⾜够强⼤的时候,需要⽤到属性就会很多,这时候就能体会到 builder 模式的强⼤呢。⽐如可以⽀持设置 Gravity,⽀持传⼊不同的targetView。现在我是直接 imageView 写死的。 protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main);

mText = findViewById(); ckable(true); lickListener(new kListener() { @Override public void onClick(View v) { showCenterView(mText); } }); } public void showCenterView(View view) { r builder = lder(); horView(view); FloatingManager manager = (); nterView(); } 下⾯是 采⽤的是 builder 模式简单封装的⼀个管理类:public class FloatingManager { private View mAnchorView; private String mTitle; private ViewGroup mRootView; public static Builder getBuilder() { return new Builder(); } static class Builder { private FloatingManager mManager; public FloatingManager build() { return mManager; } public Builder() { mManager = new FloatingManager(); } public Builder setAnchorView(View view) { horView(view); return this; } public Builder setTitle(String title) { le(title); return this; } } public void setAnchorView(View view) { mAnchorView = view; } public void setTitle(String title) { = title; } public void showCenterView() { if (mAnchorView == null) { return; } Activity activity = (Activity) text(); mRootView = ewById(t); Rect anchorRect = new Rect(); Rect rootViewRect = new Rect(); balVisibleRect(anchorRect); balVisibleRect(rootViewRect); // 创建 imageView ImageView imageView = new ImageView(activity); geDrawable(ources().getDrawable(_launcher)); w(imageView); // 调整显⽰区域⼤⼩ Params params = (Params) outParams(); = 100; = 100; outParams(params); // 设置居中显⽰ ( - + (ght() - 100) / 2); ( + (th() - 100) / 2); }}其实添加以后,还得考虑事件的点击之类的,⽐如可以通过设置回调,当点击引导动画的时候,先隐藏动画,再去主动促发按钮的点击逻辑等。还有就是上⾯写的管理类存在重复添加 imageView 的逻辑漏洞,应该在每次添加前都做⼀个检查,确保不会重复添加。到这⾥,整个知识点就讲完了。

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689427641a246468.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信