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

仿QQ空间根据位置弹出PopupWindow显示更多操作效果的更多相关文章

  1. Android项目实战(十七):QQ空间实现(二)—— 分享功能 / 弹出PopupWindow

    这是一张QQ空间说说详情的截图. 分析: .点击右上角三个点的图标,在界面底部弹出一个区域,这个区域有一些按钮提供给我们操作 .当该区域出现的时候,详情界面便灰了,也说成透明度变化了 .当任意选了一个 ...

  2. (转载)Android项目实战(十七):QQ空间实现(二)—— 分享功能 / 弹出PopupWindow

    Android项目实战(十七):QQ空间实现(二)—— 分享功能 / 弹出PopupWindow   这是一张QQ空间说说详情的截图. 分析: 1.点击右上角三个点的图标,在界面底部弹出一个区域,这个 ...

  3. 【Android UI设计与开发】7.底部菜单栏(四)PopupWindow 实现显示仿腾讯新闻底部弹出菜单

    前一篇文章中有用到 PopupWindow 来实现弹窗的功能.简单介绍以下吧. 官方文档是这样解释的:这就是一个弹出窗口,可以用来显示一个任意视图.出现的弹出窗口是一个浮动容器的当前活动. 1.首先来 ...

  4. 仿iOS底部弹出popUpWindow

    上面为弹出来的效果 popUpWindow布局: <?xml version="1.0" encoding="utf-8"?> <Linear ...

  5. Fragment,仿QQ空间

    转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451          在今天的这篇文章当中,我依然会以实战加理论结合 ...

  6. 仿QQ空间和微信朋友圈,高解耦高复用高灵活

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  7. 仿QQ空间动态界面分享

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  8. Android Animation动画实战(二):从屏幕底部弹出PopupWindow

    在这篇文章之前,我已经陆陆续续写了几篇博客,介绍了Android Animation是如何使用的,有还不明白的,可以点击查看: 1. Android Animation动画详解(一): 补间动画 2. ...

  9. JS仿QQ空间鼠标停在长图片时候图片自动上下滚动效果

    JS仿QQ空间鼠标停在长图片时候图片自动上下滚动效果 今天是2014年第一篇博客是关于类似于我们的qq空间长图片展示效果,因为一张很长的图片不可能全部把他展示出来,所以外层用了一个容器给他一个高度,超 ...

随机推荐

  1. 乐乎环球WiFi

    乐乎环球WiFi招商加盟 随身WiFi设备 乐乎环球Wifi是由北京蔚蓝创智科技有限公司研发的产品,是一款可以在全球100多个国家和地区实现免漫游4G高速上网的随身WiFi设备.和普通MiFi设备相比 ...

  2. webService

    什么是webService WebService,顾名思义就是基于Web的服务.它使用Web(HTTP)方式,接收和响应外部系统的某种请求.从而实现远程调用.  1:从WebService的工作模式上 ...

  3. Windows 7 上安装Visual Studio 2015 失败解决方案

    安装之前先要看看自己的系统支不支持,具体的可以看:https://www.visualstudio.com/en-us/visual-studio-2015-system-requirements-v ...

  4. Phaser-游戏之旅

    虽然这个小游戏逻辑不是很复杂,但为了熟悉Phaser这个游戏框架的使用方法所以就选择了它. 另外第一次在项目中尝试使用ES6,之后利用babel进行转换. 自动化构建:gulp(其他文件复制和解析) ...

  5. 架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)

    在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务.通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解. 远程调 ...

  6. 牛顿插值法——用Python进行数值计算

    拉格朗日插值法的最大毛病就是每次引入一个新的插值节点,基函数都要发生变化,这在一些实际生产环境中是不合适的,有时候会不断的有新的测量数据加入插值节点集, 因此,通过寻找n个插值节点构造的的插值函数与n ...

  7. Integer.parseInt 引发的血案

    Integer.parseInt 处理一个空字符串, 结果出错了, 程序没有注意到,搞了很久, 引发了血案啊!! 最后,终于 观察到了, 最后的部分: Caused by: java.lang.NoC ...

  8. 配置hibernate,Struts。文件

    hibernate文件配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernat ...

  9. Atitit 编程语言编程方法的进化演进 sp  COP ,AOP ,SOP

    Atitit 编程语言编程方法的进化演进 sp  COP ,AOP ,SOP 1.1.  Sp  oop>>COP ,AOP ,SOP1 1.2. Sp  oop 结构化方法SP(Stru ...

  10. Android笔记——Handler Runnable与Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...