Android开发仿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的用法,思路清晰一步一步实现很简单。

以上所述是小编给大家介绍的Android开发仿QQ空间根据位置弹出PopupWindow显示更多操作效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

时间: 2016-12-08

Android开发实现popupWindow弹出窗口自定义布局与位置控制方法

本文实例讲述了Android开发实现popupWindow弹出窗口自定义布局与位置控制方法.分享给大家供大家参考,具体如下: 布局文件: 主布局文件:activity_main: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q

PopupWindow自定义位置显示的实现代码

一.概述 在Android中弹出式菜单(以下称弹窗)是使用十分广泛的一种菜单呈现方式,弹窗为用户交互提供了便利.关于弹窗的实现大致有以下两种方式AlertDialog和PopupWindow,当然网上也有使用Activity并配合Dialog主题的方式实现弹窗,有兴趣的朋友也可以去研究一下.对于AlertDialog和PopupWindow两者最主要的区别就是显示的位置问题: (1)AlertDialog在位置显示上是固定的 (2)PopupWindow相对比较随意,能够在主屏幕的任意位置显示.

Android编程中PopupWindow的用法分析【位置、动画、焦点】

本文实例讲述了Android编程中popupwindow用法.分享给大家供大家参考,具体如下: 在Android中有很多级别的Window,不同级别的Window按照z-index方向分布.下面看看Android控件(view)PopupWindow的用法(位置.动画.焦点). 1.创建PopouWindow及相关参数设置 //创建一个包含自定义view的PopupWindow private PopupWindow makePopupWindow(Context cx) { PopupWind

Android编程中Perferences的用法实例分析

本文实例讲述了Android编程中Perferences的用法.分享给大家供大家参考,具体如下: 浏览手机的/data/data/目录中的各个package的目录,经常会看到有一个shared_prefs文件夹,里面有一个包名_preferences.xml文件,这个文件就是要说的主角,下面简称他为配置文件: 这个文件类似于一个配置文件的角色,记录应用的一些属性值,比如如果你的应用提供了指导用户使用的向导功能,那么估计肯定会提供选项让用户来关闭这个功能,那么你可以将这个开关放置在这个文件里,下次

Android编程中HTTP服务用法详解

本文实例讲述了Android编程中HTTP服务用法.分享给大家供大家参考,具体如下: 在Android中,除了使用java.net包下的API访问HTTP服务之外,我们还可以换一种途径去完成工作.Android SDK附带了Apache的HttpClient API.Apache HttpClient是一个完善的HTTP客户端,它提供了对HTTP协议的全面支持,可以使用HTTP GET和POST进行访问.下面我们就结合实例,介绍一下HttpClient的使用方法. 我们新建一个http项目,项目

Android编程中自定义dialog用法实例

本文实例讲述了Android编程中自定义dialog用法.分享给大家供大家参考,具体如下: dialog是android中提供的一组弹出提示框,非常好用,可是它的样式是一个定式,有时候我们需求定义一些自己的样式 1.定义一个样式文件,此文件继承自Theme.Dialog,在style.xml文件中建立一个自己的样式 <style name="addNoteType_error_Dialog" parent="@android:Theme.Dialog">

Android编程之重力感应用法分析

本文实例讲述了Android编程之重力感应用法.分享给大家供大家参考,具体如下: 重力感应主要是依靠手机的加速度传感器(accelerometer)来实现 在Android的开发中一共有八种传感器但是不一定每一款真机都支持这些传感器.因为很多功能用户根本不care的所以可能开发商会把某些功能屏蔽掉.还是得根据真机的实际情况来做开发,下面主要讨论加速度传感器的具体实现方式,传感器名称如下: 加速度传感器(accelerometer) 陀螺仪传感器(gyroscope) 环境光照传感器(light)

Android编程之通知栏的用法小结

本文实例总结了Android编程中通知栏的用法.分享给大家供大家参考,具体如下: 很久没有使用Android的通知功能了,今天把两年前的代码搬出来一看,发现很多方法都废弃了,代码中各种删除线看的十分不爽.于是乎,打开Google,查看官方文档,学习最新的发送通知栏消息的方法. 本文中的代码均参照谷歌官方文档编写: http://developer.android.com/guide/topics/ui/notifiers/notifications.html 1.首先,获取系统的通知服务: 复制

Android开发中PopupWindow用法实例分析

本文实例分析了Android开发中PopupWindow用法.分享给大家供大家参考,具体如下: private TextView tv_appmanager_title; private ListView lv_app_manager; private LinearLayout ll_appmanager_loading; private AppManagerProvider provider; private List<AppManagerInfo> infos ; private AppM

Android编程中selector背景选择器用法实例分析

本文实例讲述了Android编程中selector背景选择器用法.分享给大家供大家参考,具体如下: 在Android开发过程中,经常对某一View的背景在不同的状态下,设置不同的背景,增强用户体验.如果按钮,在按下时,背景变化,如果在代码中动态设置,相对比较麻烦.Android为我们提供了selector背景选择器可以非常方便的解决这一问题. Selector的结构描述: 1.android:state_pressed="true/false" true:表示按下状态下使用,false

Android编程中Handler原理及用法实例分析

本文实例讲述了Android编程中Handler用法.分享给大家供大家参考,具体如下: 在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化.有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过接收到的消息更新主UI线程的内容. 我们假设在一个UI界面上面,有一个按钮,当点击这个按钮的时候,会进行网络连接,并把网络上的一个字符串拿下来显示到界面上的一个 TextView上面,这时就出现了一个问题,如果这个网络连接的延迟过大,可能是10

Android编程中常用适配器及自定义适配器用法实例分析

本文实例讲述了Android编程中常用适配器及自定义适配器用法.分享给大家供大家参考,具体如下: 一.适配器. 顾名思义,就是把一些数据给弄得适当,适合以便于在View上显示.可以看作是界面数据绑定的一种理解.它所操纵的数据一般都是一些比较复杂的数据,如数组,链表,数据库,集合等.适配器就像显示器,把复杂的东西按人可以接受的方式来展现. 那么适配器是怎么处理得到的数据,并把它显示出来的呢.其实很简单,说白了适配器它也是一个类,在类里面它实现了父类的这几个方法: publicint getCoun