zoukankan      html  css  js  c++  java
  • 仿QQ空间根据位置弹出PopupWindow显示更多操作效果

    我们打开QQ空间的时候有个箭头按钮点击之后弹出PopupWindow会根据位置的变化显示在箭头的上方还是下方,比普通的PopupWindow弹在屏幕中间显示好看的多。

    先看QQ空间效果图:

                               

    这个要实现这个效果可以分几步进行

    1.第一步自定义PopupWindow,实现如图的样式,这个继承PopupWindow自定义布局很容易实现

    2.得到点击按钮的位置,根据位置是否在屏幕的中间的上方还是下方,将PopupWindow显示在控件的上方或者下方

    3.适配问题,因为PopupWindow上面的操作列表是动态的所以要自定义listView

    4.动画效果+背景变暗

    通过步骤分析,我们就很清晰的了解我们要做什么,话不多说,从第一步开始吧

    下面自定义PopupWindow实现效果

    1.重写listView,重新计算高度(一般也应用于解决ScrollView嵌套listView只显示一行的问题)

    public class MyListView extends ListView {
    public MyListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    }

    public MyListView(Context context) {
    super(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
    MeasureSpec.AT_MOST));
    }
    }

    2.自定义PopupWindow的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="right">
    <ImageView
    android:id="@+id/arrow_up"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="28dp"
    android:src="@drawable/arrow_up_white"
    android:visibility="visible"/>
    <com.widget.MyListView
    android:id="@+id/lv_list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/normal_margin8"
    android:layout_marginTop="-1dp"
    android:layout_marginBottom="-1dp"
    android:dividerHeight="0dp"
    android:layout_marginLeft="@dimen/normal_margin8"
    android:layout_marginRight="@dimen/normal_margin8"
    android:scrollbars="none"
    android:background="@drawable/custom_white"
    android:divider="@null"></com.widget.MyListView>
    <ImageView
    android:id="@+id/arrow_down"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="28dp"
    android:src="@drawable/arrow_down_white"
    android:visibility="visible"/>
    </LinearLayout>

    2.PopupWindow弹出动画以及消失动画

    popshow_operation_anim_down.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromXScale="0.0"
    android:toXScale="1.0"
    android:fromYScale="0.0"
    android:toYScale="1.0"
    android:pivotX="90%"
    android:pivotY="0%"
    android:fillAfter="false"
    android:duration="300" >
    </scale>
    </set>
    popshow_operation_anim_up.xml
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromXScale="0.0"
    android:toXScale="1.0"
    android:fromYScale="0.0"
    android:toYScale="1.0"
    android:pivotX="90%"
    android:pivotY="100%"
    android:fillAfter="false"
    android:duration="250" >
    </scale>
    </set>

     消失动画是渐隐动画可以自己定义,同理。

    3.重写PopupWindow了

    public class CustomOperationPopWindow extends PopupWindow {
    private Context context;
    private View conentView;
    private View backgroundView;
    private Animation anim_backgroundView;
    private MyListView listView;
    private TypeSelectPopuAdapter selectAdapter;
    ImageView arrow_up, arrow_down;
    List<TypeSelect> typeSelectlist = new ArrayList<>();
    int[] location = new int[2];
    private OnItemListener onItemListener;
    private AdapterView.OnItemClickListener onItemClickListener;

    public interface OnItemListener {
    public void OnItemListener(int position, TypeSelect typeSelect);
    }

    ;

    public void setOnItemMyListener(OnItemListener onItemListener) {
    this.onItemListener = onItemListener;
    }

    public CustomOperationPopWindow(Context context) {
    this.context = context;
    initView();
    }

    public CustomOperationPopWindow(Context context, List<TypeSelect> typeSelectlist) {
    this.context = context;
    this.typeSelectlist = typeSelectlist;
    initView();
    }

    private void initView() {
    this.anim_backgroundView = AnimationUtils.loadAnimation(context, R.anim.alpha_show_anim);
    LayoutInflater inflater = (LayoutInflater) context
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.conentView = inflater.inflate(R.layout.view_operation_popupwindow, null);
    // 设置SelectPicPopupWindow的View
    this.setContentView(conentView);
    // 设置SelectPicPopupWindow弹出窗体的宽
    this.setWidth(LayoutParams.MATCH_PARENT);
    // 设置SelectPicPopupWindow弹出窗体的高
    this.setHeight(LayoutParams.WRAP_CONTENT);
    // 设置SelectPicPopupWindow弹出窗体可点击
    this.setFocusable(true);
    this.setOutsideTouchable(true);
    // 刷新状态
    this.update();
    // 实例化一个ColorDrawable颜色为半透明
    ColorDrawable dw = new ColorDrawable(0000000000);
    // 点back键和其他地方使其消失,设置了这个才能触发OnDismisslistener ,设置其他控件变化等操作
    this.setBackgroundDrawable(dw);
    // 设置SelectPicPopupWindow弹出窗体动画效果
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
    this.listView = (MyListView) conentView.findViewById(R.id.lv_list);
    this.arrow_up = (ImageView) conentView.findViewById(R.id.arrow_up);
    this.arrow_down = (ImageView) conentView.findViewById(R.id.arrow_down);

    //设置适配器
    this.selectAdapter = new TypeSelectPopuAdapter(context, typeSelectlist,
    R.layout.item_operation_popu);
    this.listView.setAdapter(selectAdapter);
    this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    if (isShowing()) {
    dismiss();
    }
    onItemListener.OnItemListener(position, typeSelectlist.get(position));
    }
    });
    this.setOnDismissListener(new OnDismissListener() {
    @Override
    public void onDismiss() {
    if (backgroundView != null) {
    backgroundView.setVisibility(View.GONE);
    }
    }
    });
    }

    //设置数据
    public void setDataSource(List<TypeSelect> typeSelectlist) {
    this.typeSelectlist = typeSelectlist;
    this.selectAdapter.notifyDataSetChanged();
    }


    /**
    * 没有半透明背景 显示popupWindow
    *
    * @param
    */
    public void showPopupWindow(View v) {
    v.getLocationOnScreen(location); //获取控件的位置坐标
    //获取自身的长宽高
    conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    if (location[1] > MainApplication.SCREEN_H / 2 + 100) { //MainApplication.SCREEN_H 为屏幕的高度,方法可以自己写
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
    arrow_up.setVisibility(View.GONE);
    arrow_down.setVisibility(View.VISIBLE);
    this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight());
    } else {
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_down);
    arrow_up.setVisibility(View.VISIBLE);
    arrow_down.setVisibility(View.GONE);
    this.showAsDropDown(v, 0, 0);
    }
    }

    /**
    * 携带半透明背景 显示popupWindow
    *
    * @param
    */
    public void showPopupWindow(View v, View backgroundView) {
    this.backgroundView = backgroundView;
    v.getLocationOnScreen(location); //获取控件的位置坐标
    //获取自身的长宽高
    conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    backgroundView.setVisibility(View.VISIBLE);
    //对view执行动画
    backgroundView.startAnimation(anim_backgroundView);
    if (location[1] > MainApplication.SCREEN_H / 2 + 100) { //若是控件的y轴位置大于屏幕高度的一半,向上弹出
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
    arrow_up.setVisibility(View.GONE);
    arrow_down.setVisibility(View.VISIBLE);
    this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight()); //显示指定控件的上方
    } else {
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_down); //反之向下弹出
    arrow_up.setVisibility(View.VISIBLE);
    arrow_down.setVisibility(View.GONE);
    this.showAsDropDown(v, 0, 0); //显示指定控件的下方
    }
    }
    /**
    * 显示popupWindow 根据特殊要求高度显示位置
    *
    * @param
    */
    public void showPopupWindow(View v, View backgroundView,int hight) {
    this.backgroundView = backgroundView;
    v.getLocationOnScreen(location);
    //获取自身的长宽高
    conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    backgroundView.setVisibility(View.VISIBLE);
    //对view执行动画
    backgroundView.startAnimation(anim_backgroundView);
    if (location[1] > MainApplication.SCREEN_H / 2 + 100) {
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
    arrow_up.setVisibility(View.GONE);
    arrow_down.setVisibility(View.VISIBLE);
    this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight()-hight);
    } else {
    this.setAnimationStyle(R.style.operation_popwindow_anim_style_down);
    arrow_up.setVisibility(View.VISIBLE);
    arrow_down.setVisibility(View.GONE);
    this.showAsDropDown(v, 0, 0);
    }
    }
    }

     4.代码中的用法

        1.

    CustomOperationPopWindow  customOperationPopWindow = new CustomOperationPopWindow(this, operationTypeSelectlist);
    customOperationPopWindow.setOnItemMyListener(new CustomOperationPopWindow.OnItemListener() {
    @Override
    public void OnItemListener(int position, TypeSelect typeSelect) {
    //此处实现列表点击所要进行的操作
    }
    });

       2.

    textView.setOnClickListener(new View.OnClickListener() {
        @Override
    public void onClick(View v) {
    customOperationPopWindow.showPopupWindow(textView);//可以传个半透明view v_background过去根据业务需要显示隐藏
        }
    });

     5.最终实际效果

                            

                 

    以上代码为几乎主要全部代码,主要是PopupWindow的用法,思路清晰一步一步实现很简单。

  • 相关阅读:
    解决使用intellij idea开发MAVEN项目在target目录下不存在mapper.xml文件
    Mybatis中接口和对应的mapper文件位置配置详解
    Mybatis(1、核心配置文件、Properties、Settings、typeAliases...)
    nginx的常用负载均衡算法,分别是
    修改JVM的参数、Jstat、Jstack、gclog
    shiro 系列
    sso简单原理及实现
    Thymeleaf3.0内容
    Thymeleaf模板引擎+Spring整合使用方式的介绍
    给 IIS Express 配置虚拟目录
  • 原文地址:https://www.cnblogs.com/teamblog/p/6145768.html
Copyright © 2011-2022 走看看