>>分享Android开发相关的技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 21435 个阅读者 刷新本主题
 * 贴子主题:  Android炫酷菜单 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-01-01 23:12:29     消息  查看  搜索  好友  邮件  复制  引用

前言:
今天要给大家展示安卓弹出菜单的效果,当然并非原创,仿写别人的,写得不好的地方,请见谅~
概述:
  • 环境:Android Studio 3.42
  • 语言:Java
  • 特点:简单,易懂,效果爆炸
展示:
   点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
one.gif
简要说明:这里重写了

popupWindow

,实现了popupWindow里图片

item

的点击效果,而这个demo里的难点就在这两个地方
进入代码部分
  • popupWindow类

    自定义属性和构造方法

private final  int CONST_R = 100;//圆半径
    private final  int CONST_ICON_SIZE = 35;//dpValue值
    private int itempadding = 0;
    private Context context;
    private FrameLayout frameLayout;
    //自定义圆形背景
    private View circle;
    //保存控件对象
    private List<View> itemViews = new ArrayList<>();
    //圆心显示的图行控件
    private ImageView imageView;
    private OnPathItemClickListener mOnPathItemClickListener;//记录监听对象
    //设置监听对象的方法
    public void setOnPathItemClickListener(OnPathItemClickListener onPathItemClickListener){
        this.mOnPathItemClickListener = onPathItemClickListener;
    }
    //默认构造方法
    protected PathPopupWindow(){}
    //覆盖默认的构造方法
    public PathPopupWindow(Context context, List<PathItem> items){
        //实现构造方法的传递 执行下面的构造方法
        this(context,items, Color.BLACK,12,Color.TRANSPARENT);
    }
    //具体执行的构造方法
    public PathPopupWindow(Context context, List<PathItem> items, int textColor, int textSize, int itembgResId) {
       super(context);
       this.context = context;
       //设置获取焦点
       setFocusable(true);
       //计算item之间的间距 使得效果显示一致
       itempadding = DensityUtil.dip2px(context, 8);
       //计算控件的宽度
        int itemWidth = DensityUtil.dip2px(context,CONST_ICON_SIZE + textSize + 4) + itempadding * 2;
        //计算宽高
        int width = DensityUtil.dip2px(context, CONST_R * 2 + 30) + itemWidth;
        int height = DensityUtil.dip2px(context, CONST_R * 2 + 30 + textSize) + itemWidth;
        //设置宽高
        setWidth(width);
        setHeight(height);
        setBackgroundDrawable(new ColorDrawable());
        frameLayout = new FrameLayout(context);
        circle = new View(context);
        circle.setBackgroundResource(R.drawable.bg_circle);
        //计算半径
        int Radius = DensityUtil.dip2px(context,CONST_R);
        //计算circle与frameLayout之间的间距
        int padding = (width - Radius * 2)/2;
        //设置布局参数 大小为半径的2倍
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(Radius*2,Radius*2);
        params.leftMargin = params.topMargin = (width - Radius * 2) / 2;
        //将圆添加到frameLayout里
        frameLayout.addView(circle,params);
        for (int i = 0;i<items.size();i++){
            //创建线性布局对象 里面包含了所需要的图片控件
            LinearLayout linearLayout =createItem(i,items.get(i),textColor,textSize,itembgResId);
            int x = (int) (Math.cos(2 * Math.PI / items.size()*i + Math.PI/2)*Radius);
            int y = (int) (Math.sin(2 * Math.PI / items.size() * i + Math.PI / 2) * Radius);
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(itemWidth,itemWidth);
            lp.leftMargin = Radius + x + padding - itemWidth / 2;
            lp.topMargin = Radius - y + padding - itemWidth /2;
            //将线性布局对象添加到frameLayout里
            frameLayout.addView(linearLayout,lp);
            //保存线性布局对象
            itemViews.add(linearLayout);
        }
        //设置圆心显示的控件图片 这里是天猫
        imageView = new ImageView(context);
        imageView.setImageResource(R.drawable.tianmao);
        FrameLayout.LayoutParams iv_lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        iv_lp.gravity = Gravity.CENTER;
        iv_lp.topMargin = -DensityUtil.dip2px(context,textSize) / 2;
        frameLayout.addView(imageView,iv_lp);
        setContentView(frameLayout);
        frameLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //自定义方法设置动画效果隐藏控件图片
                dismiss();
            }
        });
    }

开始时的动画 显示图片控件 旋转 缩放 平移

public void show(View view){
    showAtLocation(view, Gravity.CENTER, 0, 0);
    //这是一个代码块 执行完以后才能执行下一个
    {
        // 旋转动画 对应圆心处天猫的动画演示效果
        RotateAnimation rotate = new RotateAnimation(360, 0,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        //设置动画时间
        rotate.setDuration(500);
        //设置动画结束保持结束时的画面
        rotate.setFillAfter(true);
        //开启动画
        imageView.startAnimation(rotate);
    }
    {
        //放大动画 对应圆一开始逐渐变大的演示效果
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.3f, 1f, 0.3f, 1f, Animation.RELATIVE_TO_SELF,0.5f,
                Animation.RELATIVE_TO_SELF,0.5f);
        scaleAnimation.setDuration(300);
        scaleAnimation.setFillAfter(true);
        circle.startAnimation(scaleAnimation);
    }
    int Radius = DensityUtil.dip2px(context, CONST_R);
        //平移动画 对应圆形边缘的控件图片演示效果
    for(int i = 0;i<itemViews.size();i++){
        int x = (int) (Math.cos(2 * Math.PI / itemViews.size() * i + Math.PI / 2) * Radius);
        int y = (int) (Math.sin(2 * Math.PI / itemViews.size() * i + Math.PI / 2) * Radius);
        TranslateAnimation translateAnimation = new TranslateAnimation(-x, 0F, y, 0F);
        translateAnimation.setDuration(500);
        translateAnimation.setFillAfter(true);
        translateAnimation.setInterpolator(new OvershootInterpolator(2F));
        itemViews.get(i).startAnimation(translateAnimation);
    }
}

点击天猫隐藏控件图片的动画

//默认未隐藏
private boolean isdimissing = false;
    @Override
    public void dismiss() {
        //如果点击天猫成功隐藏图片 自动返回 结束
        if(isdimissing || !isShowing()){
            return;
        }
        isdimissing = true;
        {
            RotateAnimation rotate = new RotateAnimation(0, 360,
            Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rotate.setDuration(500);
            rotate.setFillAfter(false);
            imageView.startAnimation(rotate);
        }
        {
            ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0.3f, 1f, 0.3f, Animation.RELATIVE_TO_SELF,0.5f,
            Animation.RELATIVE_TO_SELF,0.5f);
            scaleAnimation.setDuration(500);
            scaleAnimation.setFillAfter(false);
            circle.startAnimation(scaleAnimation);
        }
        int Radius = DensityUtil.dip2px(context, CONST_R);
        for(int i = 0;i<itemViews.size();i++){
            int x = (int) (Math.cos(2 * Math.PI / itemViews.size() * i + Math.PI / 2) * Radius);
            int y = (int) (Math.sin(2 * Math.PI / itemViews.size() * i + Math.PI / 2) * Radius);
            TranslateAnimation translateAnimation = new TranslateAnimation(0F, -x, 0F, y);
            translateAnimation.setDuration(300);
            translateAnimation.setFillAfter(false);
            if(i == itemViews.size() - 1){
                translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                    public void onAnimationStart(Animation animation) {
                    }
                    public void onAnimationRepeat(Animation animation) {
                    }
                    public void onAnimationEnd(Animation animation) {
                        //隐藏popupWindow
                        PathPopupWindow.super.dismiss();
                        isdimissing = false;
                    }
                });
            }
            itemViews.get(i).startAnimation(translateAnimation);
        }
    }

  • pathItem类
    这个类定义了三个属性 以及 三个构造方法
public class PathItem {
//控件名字
    public String name;
//控件图片资源RedId
    public int imageResId;
//控件背景资源
    public int backgroundResId;
//构造方法
    public PathItem name(String name){
        this.name = name;
        return  this;
    }
    public PathItem imageResId(int imageResId){
        this.imageResId = imageResId;
        return this;
    }
    public PathItem backgroundResId(int backgroundResId){
        this.backgroundResId = backgroundResId;
        return this;
    }
}

  • DensityUtil类
这个类定义了许多静态方法 当然不是所有的方法都会用到  

public class DensityUtil {
//默认构造方法
    public DensityUtil(){}
    /*获取屏幕像素点scale来保证控件在不同设备里的相对位置一致,方法的具体使用
    int itempadding = DensityUtil.dip2px(context, 8);*/

    public static int dip2px(Context context,float dpValue){
        float scale = context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale + 0.5f);
    }
    
    public static int px2dip(Context context, float pxValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int)(pxValue / scale + 0.5F);
    }
    
    public static float dip2pxf(Context context, int dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (float)dpValue * scale + 0.5F;
    }
    public static float dip2pxf(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return dpValue * scale + 0.5F;
    }

最后回到

MainActivity

实现popupWindow的显示
  • MainActivity类
    首先给

    activity_main

    布局文件默认的控件TextView设置id号
<TextView
        android:id="@+id/tv_hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

  然后回到MainActivity里通过设置的id号找到对应的TextView并设置点击事件,实现popupWindow的显示,以及对应控件图片的点击效果,当然也包括pathItemList的初始化  

public class MainActivity extends AppCompatActivity {

    private TextView tv_hello;
    private List<PathItem> pathItemList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_hello = findViewById(R.id.tv_hello);
        pathItemList = new ArrayList<>();
        pathItemList.add(new PathItem().name("苏宁易购").imageResId(R.drawable.ic_snyg).backgroundResId(R.drawable.bg_blue_oval));
        pathItemList.add(new PathItem().name("天猫超市").imageResId(R.drawable.ic_tmcs).backgroundResId(R.drawable.bg_blue_oval));
        pathItemList.add(new PathItem().name("天猫国际").imageResId(R.drawable.ic_tmgj).backgroundResId(R.drawable.bg_blue_oval));
        pathItemList.add(new PathItem().name("聚划算").imageResId(R.drawable.ic_jhs).backgroundResId(R.drawable.bg_blue_oval));
        tv_hello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PathPopupWindow popupWindow = new PathPopupWindow(MainActivity.this,pathItemList);
                popupWindow.setOnPathItemClickListener(new PathPopupWindow.OnPathItemClickListener() {
                    @Override
                    public void onItemClick(int position, PathItem item) {
  Toast.makeText(MainActivity.this,"点击了--->"+item.name,Toast.LENGTH_LONG).show();
                    }
                });
                popupWindow.show(view);
            }
        });
    }
}

  总结:这个项目让我了解了popupWindow的使用,感觉自己在小白的基础上又进了一步,感谢原文博主的分享,也感谢大家的阅读
博文地址:https://blog.csdn.net/xu_coding/article/details/81515421

----------------------------
原文链接:https://www.jianshu.com/p/ad7893672123


[这个贴子最后由 flybird 在 2020-01-01 23:28:25 重新编辑]
  Java面向对象编程-->面向对象开发方法概述之开发思想(上)
  JavaWeb开发-->JavaWeb应用入门(Ⅰ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->客户端协议处理框架
  精通Spring-->Vue简介
  Vue3开发-->创建综合购物网站应用
  Android自动化测试之Robotium学习
  Android中Activity之间的通信
  Android静默安装的实现
  Android之TabHost
  Android中shape的使用
  Android Service的用法
  Android DownloadManager用法举例
  Android的init过程详解
  Android自定义组件
  Android API 中Toast类的用法
  Android开发实践:Android.mk模板
  Android Action Bar 自定义View
  Android Broadcast receiver 编程-Mobile and Linux Develop...
  安卓隐藏标题栏方法
  自定义ViewGroup和FrameLayout实现轮播图(包括底部小圆点)
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。