Android 必知必会
来源:互联网 发布:免费数据库同步软件 编辑:程序博客网 时间:2024/06/06 02:18
如果移动端访问不佳,请访问 ==> Github 版
近期有网友根据 Android 必知必会 - DialogFragment 使用总结 做一些业务,但是目标却是用 DialogFragment 实现类似 PopupWindow 效果:
- 只拦截自身所占空间部分的事件,其余空间的点击事件不处理
- 可以根据某个 View 定位自身位置
虽然在功能上 PopupWindow 更符合需要,但是使用 DialogFragment 代码更简洁、更方便封装功能模块。
基础知识点
WindowManager.LayoutParams.flags
WindowManager.LayoutParams.flags
修改 Window 的表现行为
/** * Various behavioral options/flags. Default is none. * * @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON * @see #FLAG_DIM_BEHIND * @see #FLAG_NOT_FOCUSABLE * @see #FLAG_NOT_TOUCHABLE * @see #FLAG_NOT_TOUCH_MODAL * @see #FLAG_TOUCHABLE_WHEN_WAKING * @see #FLAG_KEEP_SCREEN_ON * @see #FLAG_LAYOUT_IN_SCREEN * @see #FLAG_LAYOUT_NO_LIMITS * @see #FLAG_FULLSCREEN * @see #FLAG_FORCE_NOT_FULLSCREEN * @see #FLAG_SECURE * @see #FLAG_SCALED * @see #FLAG_IGNORE_CHEEK_PRESSES * @see #FLAG_LAYOUT_INSET_DECOR * @see #FLAG_ALT_FOCUSABLE_IM * @see #FLAG_WATCH_OUTSIDE_TOUCH * @see #FLAG_SHOW_WHEN_LOCKED * @see #FLAG_SHOW_WALLPAPER * @see #FLAG_TURN_SCREEN_ON * @see #FLAG_DISMISS_KEYGUARD * @see #FLAG_SPLIT_TOUCH * @see #FLAG_HARDWARE_ACCELERATED * @see #FLAG_LOCAL_FOCUS_MODE * @see #FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS */
以上可以看到它有很多可选项,加上可以多个相互组合,能满足很多需求,这里重点关注三个属性值:
FLAG_NOT_TOUCH_MODAL
Window flag: even when this window is focusable (its
FLAG_NOT_FOCUSABLE
is not set), allow any pointer events outside of the window to be sent to the windows behind it.(API level 1)
FLAG_TRANSLUCENT_NAVIGATION
Window flag: request a translucent navigation bar with minimal system-provided background protection.
(API level 19)
FLAG_TRANSLUCENT_STATUS
Window flag: request a translucent status bar with minimal system-provided background protection.
(API level 19)
更详细的介绍请点击 文档
其中 FLAG_NOT_TOUCH_MODAL
可达到『只拦截自身所占空间部分的事件,其余空间的点击事件不处理』的需求,而 FLAG_TRANSLUCENT_NAVIGATION
和 FLAG_TRANSLUCENT_STATUS
主要是用来调整使用沉浸式状态栏时显示自身位置不正确的问题。
获取 View 位置的时机
如果需要让 DialogFragment 在 onCreate()
等生命周期函数内直接调用显示到某个 View 的位置处,可能无法正确获取到该 View 的坐标,具体参考 Android必知必会-获取View坐标和长宽的时机 一文。
但是,如果在界面显示给用户后,DialogFragment 的显示交给用户触发的话,就不需要在意这个问题了。
代码实现
TopFragment.java
public class TopFragment extends DialogFragment { private static final String EXT_Y = "y value"; private static final String EXT_BAR = "isTranslucentDecor"; private int y; private boolean isTranslucentDecor; public static TopFragment getInstant(int y) { return getInstant(y, false); } public static TopFragment getInstant(int y, boolean isTranslucentDecor) { TopFragment fragment = new TopFragment(); Bundle ext = new Bundle(); ext.putInt(EXT_Y, y); ext.putBoolean(EXT_BAR, isTranslucentDecor); fragment.setArguments(ext); return fragment; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialogFrag); Bundle args = getArguments(); if (args != null) { y = args.getInt(EXT_Y, 0); isTranslucentDecor = args.getBoolean(EXT_BAR, false); } else { y = 0; isTranslucentDecor = false; } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { getDialog().setCanceledOnTouchOutside(false); View rootView = inflater.inflate(R.layout.fragment_top, container, false); //Do something final Window window = getDialog().getWindow(); window.setBackgroundDrawableResource(android.R.color.transparent); window.getDecorView().setPadding(0, 0, 0, 0); WindowManager.LayoutParams wlp = window.getAttributes(); wlp.width = WindowManager.LayoutParams.MATCH_PARENT; wlp.height = WindowManager.LayoutParams.WRAP_CONTENT; wlp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; if (isTranslucentDecor) { wlp.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; } wlp.gravity = Gravity.TOP;//必须为 TOP,否则定位不准确 wlp.y = y;//配合 Gravity.TOP 才能准确定位 window.setAttributes(wlp); //Debug info rootView.findViewById(R.id.vvv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getActivity(), "dialogFragment 响应了点击事件", Toast.LENGTH_SHORT).show(); } }); return rootView; }}
MainActivity.java
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.bt_menu).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { TextView title = (TextView) findViewById(R.id.tv_title); TopFragment.getInstant(title.getBottom()).show(getSupportFragmentManager(), "tags"); } });}
注意:如果当前 Activity 使用了沉浸式状态栏,需要使用 TopFragment.getInstant(int y, boolean isTranslucentDecor)
方法,并且 isTranslucentDecor
传值为 true
。
效果图
未使用沉浸式状态栏、 isTranslucentDecor
传值为 false
使用沉浸式状态栏、 isTranslucentDecor
传值为 false
,位置定位差个状态栏高度
使用沉浸式状态栏、 isTranslucentDecor
传值为 true
,位置定位修复
总结
总的来说,这里基本完成了要求的效果,但是定位只能指定其顶部开始的位置,不方便底部定位到某个 View 的上面,因为高度自适应的话,在页面渲染完成前是不能知道它的高度的。当然,你可以使用固定高度布局的方式来实现随意定位。
有什么意见或者问题可以随时联系我,共同探讨学习:
- 微博:cafeting
- Github: likfe
- CSDN:他叫自己Mr.张
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android 必知必会
- Android必知必会-Android Studio修改包名
- Android必知必会-Android Studio修改包名
- Android必知必会-Android Studio修改包名
- Android必知必会-Android Studio修改包名
- Android必知必会--GreenDao缓存
- Android HTTP必知必会
- 2016 Android App必知必会
- Android
- android
- Android
- DNS配置实例
- LeetCode-461 Hamming Distance
- jain-sip 一些类的初步理解
- Graphics—边缘填充算法
- Linux/Unix IO 多路复用之poll网络编程
- Android 必知必会
- 在ArrayList中加上Activity
- 算法导论 22.1-4 通用汇点 O(V)
- [python + pillow] 修改图片的尺寸
- 服务器提示Can’t assignrequested address的问题分析
- 【Jmeter】BeanShell断言--数据处理
- python008 -- 函数及高阶函数
- android 换肤
- python ---待修改,ATM取款系统