博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动画以及View绘制中的addview实战
阅读量:6329 次
发布时间:2019-06-22

本文共 12336 字,大约阅读时间需要 41 分钟。

一、点击按钮弹出卫星导航Button

              

1、背景:fragment中嵌套recyclerview,当点击功能键(三个点)的时候弹出如右图的导航菜单并伴随动画。

刚接到需求时,开始github上检索相似控件以提供灵感。最终采用这个。 (感谢)

2、灵感:采用根部局为framlayout将五个按钮堆在一起,并置于中间,当点击时,下面的四个按钮做动画,飞出来。点击item,recyclerview通过mRecyclerView.setTranslationY()方法进行上下移动,使buttons能全部弹出,不会被屏幕遮盖。监听到recyclerview位移动画结束后,进行buttons的弹出动画,同时将recyclerview置于不可滑动(通过重写recyclerview),增加蒙层在按钮下边,root_view上边。

3、实施:先上需要插入到root_view中xml item_buttons:(ps小技巧 : 进行测试时,当发现计算有错,或者区域绘制有错,应当给插入的布局一个底色

 初始化recyclerview的需要动画

1 private void initAnim() { 2         moveRecycler = ValueAnimator.ofFloat(1, 0); 3         moveRecycler.setDuration(500); 4         moveRecycler.setInterpolator(new AccelerateDecelerateInterpolator()); 5         moveRecycler.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 6             @Override 7             public void onAnimationUpdate(ValueAnimator valueAnimator) { 8                 float value = (float) valueAnimator.getAnimatedValue(); 9                 mRecyclerView.setTranslationY(recoverTranslationY * (1 - value));10                 shadowView.setAlpha(1 - value);11             }12         });13         moveRecycler.addListener(new AnimatorListenerAdapter() {14             @Override15             public void onAnimationEnd(Animator animation) {16                 butLists(mView);17             }18 19             @Override20             public void onAnimationStart(Animator animation) {21                 ifCanClick = false;22                 shadowView.setVisibility(View.VISIBLE);23             }24         });25         //recycler复位26         restoreRecycler = ValueAnimator.ofFloat(0, 1);27         restoreRecycler.setDuration(500);28         restoreRecycler.setInterpolator(new AccelerateDecelerateInterpolator());29         restoreRecycler.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {30             @Override31             public void onAnimationUpdate(ValueAnimator valueAnimator) {32                 float value = (float) valueAnimator.getAnimatedValue();33                 mRecyclerView.setTranslationY(recoverTranslationY * (1 - value));34                 shadowView.setAlpha(1 - value);35             }36         });37         restoreRecycler.addListener(new AnimatorListenerAdapter() {38             @Override39             public void onAnimationEnd(Animator animation) {40                 mRecyclerView.setIfScroll(true);41                 shadowView.setVisibility(View.GONE);42             }43 44             @Override45             public void onAnimationStart(Animator animation) {46                 root_view.removeView(v);47             }48         });49     }

 

初始化数据,设置adapter

1  private void refreshData() { 2         //realm中读取拼图 3         initRealmData(); 4         if (resultsList != null) { 5             galleryAdapter = new GalleryAdapter(getActivity(), resultsList); 6             mRecyclerView.setAdapter(galleryAdapter); 7             LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager. 8                     VERTICAL, false); 9             mRecyclerView.setLayoutManager(linearLayoutManager);10             galleryAdapter.setOnItemClickListener(new GalleryAdapter.OnItemClickListener() {11                 @Override12                 public void onItemClick(View view, int position) {13                     view.getLocationOnScreen(a);14                     mView = view;15                     // TODO: 2018/12/18 第一个是否需要特殊处理?16                     moveToMid(a);17                     mRecyclerView.setIfScroll(false);18                     galleryAdapter.notifyDataSetChanged();19                 }20             });21         } else {22             empty_content.setVisibility(View.VISIBLE);23         }24     }

 

计算recyclerview偏移量,增加蒙层

1 private void moveToMid(final int[] a) { 2         final int screenHeight = DeviceUtils.getScreenHeight(); 3         final int scrollHeight = screenHeight / 2 - a[1]; 4         Log.e(TAG, "moveToMid: scrollHeight:" + scrollHeight + " itemY:" + a[1] + " "); 5  6         recoverTranslationY = scrollHeight; 7         buttonTranslationY = scrollHeight; 8  9         shadowView = new View(getActivity());10         shadowView.setBackgroundColor(Color.parseColor("#66000000"));11         root_view.addView(shadowView);12         shadowView.setAlpha(0);13         shadowView.setOnClickListener(new View.OnClickListener() {14             @Override15             public void onClick(View view) {16 17             }18         });41         moveRecycler.start();42     }

 

addview,设置监听(view为功能键 三个点)

1     public void butLists(final View view) { 2         view.setVisibility(View.GONE); 3         //添加布局 4         v = LayoutInflater.from(getActivity()).inflate(R.layout.item_buttons, null, false); 5  6         Log.e(TAG, "butLists: a[0]=" + a[0] + ";a[1]=" + a[1] + ";getScreenWidth=" + DeviceUtils.getScreenWidth()); 7         v.setTranslationX(a[0] - DeviceUtils.getScreenWidth() / 2 + mView.getWidth() / 2);    //-------------------写法有待考证 8         v.setTranslationY(mView.getHeight() / 2);                               //--------------------写法有待考证 9         ImageView but_close = v.findViewById(R.id.but_close);10         but_close.setColorFilter(Color.WHITE);11         //卫星菜单相关12         final List
imageViews = new ArrayList<>();13 ImageView but_again = v.findViewById(R.id.but_again);14 ImageView but_share = v.findViewById(R.id.but_share);15 ImageView but_save = v.findViewById(R.id.but_save);16 ImageView but_delete = v.findViewById(R.id.but_delete);17 imageViews.add(but_again);18 imageViews.add(but_share);19 imageViews.add(but_save);20 imageViews.add(but_delete);21 //将弹出的四个按钮设置为功能键1.3倍 (产品需求)22 // for (int i = 0; i < imageViews.size(); i++) {23 // FrameLayout.LayoutParams l = new FrameLayout.LayoutParams(imageViews.get(i).getLayoutParams());24 // l.width = (int) (view.getWidth() * 1.3);25 // l.height = (int) (view.getHeight() * 1.3);26 // imageViews.get(i).setLayoutParams(l);27 // }28 but_close.setOnClickListener(new View.OnClickListener() {29 @Override30 public void onClick(View view1) {31 closeSectorMenu(imageViews, v);32 }33 });34 but_again.setOnClickListener(new View.OnClickListener() {35 @Override36 public void onClick(View view) {37 Toast.makeText(getActivity(), "but_again", Toast.LENGTH_SHORT).show();38 }39 });40 but_share.setOnClickListener(new View.OnClickListener() {41 @Override42 public void onClick(View view) {43 Toast.makeText(getActivity(), "but_share", Toast.LENGTH_SHORT).show();44 45 }46 });47 but_save.setOnClickListener(new View.OnClickListener() {48 @Override49 public void onClick(View view) {50 Toast.makeText(getActivity(), "but_save", Toast.LENGTH_SHORT).show();51 52 }53 });54 but_delete.setOnClickListener(new View.OnClickListener() {55 @Override56 public void onClick(View view) {57 Toast.makeText(getActivity(), "but_delete", Toast.LENGTH_SHORT).show();58 59 }60 });61 showCircleMenu(imageViews, view);62 root_view.addView(v);63 RelativeLayout.LayoutParams ll = new RelativeLayout.LayoutParams(DeviceUtils.getScreenWidth(), DeviceUtils.getScreenHeight()); //将插入的布局设置成全屏64 v.setLayoutParams(ll);65 }

 

此前直接将需要addview的布局加到指定位置,结果出现了只有功能键有监听事件,其他弹出的按钮没有。后来通过将插入的xml背景颜色置于黑色,发现整个xml以功能键为原点向右侧和下侧展开。导致弹出来的几个按钮都无点击事件。

 

经过重新计算,发现如果将插入的xml设置成屏幕宽高,那么起始的几个buttons都在屏幕中间,也就是图中target1的距离。所以最终确定插入的xml位移为上图代码中7、8行。

接下来的代码就是打开和关闭卫星栏及一些状态的监听了

1 private void showCircleMenu(final List
imageViews, View view) { 2 isShowing = true; 3 /***第一步,遍历所要展示的菜单ImageView*/ 4 for (int i = 0; i < imageViews.size(); i++) { 5 final View v = imageViews.get(i); 6 // .setLayoutParams(new FrameLayout.LayoutParams(view.getWidth()*1.3,view.getWidth()*1.3)); 7 PointF point = new PointF(); 8 /***第二步,根据菜 .fit() 9 // 单个数计算每个菜单之间的间隔角度*/10 int avgAngle = (135 / (imageViews.size() - 1));11 /**第三步,根据间隔角度计算出每个菜单相对于水平线起始位置的真实角度**/12 int angle = avgAngle * i - 45;13 Log.e(TAG, "showCircleMenu: angle:" + angle);14 15 //圆点坐标:(x0,y0)16 //半径:r17 //角度:a018 //则圆上任一点为:(x1,y1)19 //x1 = x0 + r * cos(ao * 3.14 /180 )20 //y1 = y0 + r * sin(ao * 3.14 /180 )21 22 23 //第四步,根据每个菜单真实角度计算其坐标值24 point.x = (float) -Math.cos(angle * (Math.PI / 180)) * radius1;25 point.y = (float) Math.sin(angle * (Math.PI / 180)) * radius1;26 Log.e(TAG, point.toString());27 ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(imageViews.get(i), "translationX", 0, point.x / 2);28 ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(imageViews.get(i), "translationY", 0, point.y / 2);29 //动画集合,用来编排动画30 AnimatorSet animatorSet = new AnimatorSet();31 animatorSet.setDuration(300);32 animatorSet.play(objectAnimatorX).with(objectAnimatorY);33 animatorSet.addListener(new AnimatorListenerAdapter() {34 @Override35 public void onAnimationEnd(Animator animation) {36 ifCanClick = true;37 }38 39 @Override40 public void onAnimationStart(Animator animation) {41 }42 });43 animatorSet.start();44 }45 }

 

关闭

1  private void closeSectorMenu(List
imageViews, final View v) { 2 for (int i = 0; i < imageViews.size(); i++) { 3 PointF point = new PointF(); 4 int avgAngle = (135 / (imageViews.size() - 1)); 5 int angle = avgAngle * i - 45; 6 Log.d(TAG, "angle=" + angle); 7 point.x = (float) -Math.cos(angle * (Math.PI / 180)) * radius1; 8 point.y = (float) Math.sin(angle * (Math.PI / 180)) * radius1; 9 Log.d(TAG, point.toString());10 11 ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(imageViews.get(i), "translationX", point.x / 2, 0);12 ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(imageViews.get(i), "translationY", point.y / 2, 0);13 AnimatorSet animatorSet = new AnimatorSet();14 animatorSet.setDuration(300);15 animatorSet.play(objectAnimatorX).with(objectAnimatorY);16 animatorSet.addListener(new AnimatorListenerAdapter() {17 @Override18 public void onAnimationEnd(Animator animation) {19 //点击叉,收起后recyclerview归位20 mView.setVisibility(View.VISIBLE);21 restoreRecycler.start();22 }23 });24 animatorSet.start();25 }26 isShowing = false;27 }

 

剩下就是adapter中的回调了,比较简单

1  //点击功能键 2         holder.but_func.setOnClickListener(new View.OnClickListener() { 3             @Override 4             public void onClick(View view) { 5                 if (GalleryFragment.ifCanClick){ 6                     int position = holder.getAdapterPosition(); 7                     onItemClickListener.onItemClick(holder.but_func, position); 8                     //标记点击的item的位置(没用上) 9                     posList.clear();10                     posList.add(position);11                     Log.e(TAG, "点击功能键: " + position);12                 }13             }14         });

 

接口:包括set方法

1   /**2      * 自定义的点击事件接口3      *4      * @author lish5      */6     public interface OnItemClickListener {7         void onItemClick(View view, int position);8 //      void onItemLongClick(View view, int position); //长按9     }

二、总结:

1、对view的绘制流程还是不熟练,LayoutParam不够深入了解,只会简单实用,不知原理

2、对动画的使用不够熟练

3、对计算偏移量不够熟练

 

转载于:https://www.cnblogs.com/antble/p/10140224.html

你可能感兴趣的文章
[2009.03.22 21:37:00] 肖申克的救赎-The Shawshank
查看>>
戏说Nginx(三)
查看>>
允许普通域用户登录域控制器
查看>>
比特币代码分析8 区块校验和确认
查看>>
抓包工具
查看>>
MySQL explain type详解
查看>>
无线网络连接一直显示“正在获取网络地址”
查看>>
SDWebImage 最新版详解
查看>>
历年项目、需求支持经历
查看>>
被偷走的那三年
查看>>
zabbix错误和解决办法
查看>>
linux基础命令(5)
查看>>
Exchange企业实战技巧系列之终结篇
查看>>
dell服务器硬盘的状态变成外来(foreign)命令行修复
查看>>
NetScaler结合AD限制访问用户-LDAP配置
查看>>
Info.plist与Prefix.pch修改文件位置遇到的问题及解决方法
查看>>
fastreport如何设置checkbox
查看>>
三个半月建一座高等级数据中心
查看>>
会话技术Cookie和Session
查看>>
Java方法参数传递(swap函数)(转载)
查看>>