大脚buff监视插件插件BUFF重叠问题

margin重叠问题_天垒城二_新浪博客
margin重叠问题
已知一 div 高 35px,紧邻其后的 X 元素上外边距为 15px,为该 div 设置 fixed
定位后,下列描述正确的是(D)
A.X元素上移15px
B.div与X元素之间的间距为15px​
​C.X元素以浏览器可视窗口定位
D.div与浏览器可视窗口上边界相距15px​
解析:因为X元素15px的上外边距与body的0px上外边距信息重叠了,所以body也跟着下移15px;又因为,div在父元素body内,且没有设置偏移量,所以div相对其父元素body进行绝对定位
(当绝对定位,未设置偏移量时,显示在body元素的左上角)
​垂直margin可能在一些盒模型中被折叠:
1、在常规文档流中,2个或以上的块级盒模型相邻的垂直margin会被折叠。
最终的margin值计算方法如下:
a、全部都为正值,取最大者;
b、不全是正值,则都取绝对值,然后用正值减去最大值;
c、没有正值,则都取绝对值,然后用0减去最大值。
注意:相邻的盒模型可能由DOM元素动态产生并没有相邻或继承关系。
2、相邻的盒模型中,如果其中的一个是浮动的(floated),垂直margin不会被折叠,甚至一个浮动的盒模型和它的子元素之间也是这样。
3、设置了overflow属性的元素和它的子元素之间的margin不会被折叠(overflow取值为visible除外)。
4、设置了绝对定位(position:absolute)的盒模型,垂直margin不会被折叠,甚至和他们的子元素之间也是一样。
5、设置了display:inline-block的元素,垂直margin不会被折叠,甚至和他们的子元素之间也是一样。
6、如果一个盒模型的上下margin相邻,这时它的margin可能折叠覆盖(collapse
through)它。在这种情况下,元素的位置(position)取决于它的相邻元素的margin是否被折叠。
a、如果元素的margin和它的父元素的margin-top折叠在一起,盒模型border-top的边界定义和它的父元素相同。
b、另外,任意元素的父元素不参与margin的折叠,或者说只有父元素的margin-bottom是参与计算的。如果元素的border-top非零,那么元素的border-top边界位置和原来一样。
一个应用了清除操作的元素的margin-top绝不会和它的块级父元素的margin-bottom折叠。
注意,那些已经被折叠覆盖的元素的位置对其他已经被折叠的元素的位置没有任何影响;只有在对这些元素的子元素定位时,border-top边界位置才是必需的。
7、根元素的垂直margin不会被折叠。
浮动的块级元素的margin-bottom总是与它后面的浮动块级兄弟元素(floated next in-flow
block-level sibling)的margin-top相邻,除非那个同级元素使用了清除操作。
浮动的块级元素的margin-top和它的第一个浮动块级子元素(floated first in-flow
block-level
child)的margin-top相邻(如果该元素没有border-top,没有padding-top,并且子元素没有使用清除操作)。
浮动的块级元素的margin-bottom如果符合下列条件,那么它和它的最后一个浮动块级子元素的margin-bottom相邻(如果该元素没有指定padding-bottom或border):
a、指定了height:auto
b、min-height小于元素的实际使用高度(height)
c、max-height大于元素的实际使用高度(height)
如果一个元素的min-height属性设置为0,那么它所拥有的margin是相邻的,并且它既没有border-top和border-
bottom,也没有padding-top和padding-bottom,它的height属性可以是0或auto,它不能包含一个内联的盒模型
(line box),它所有的浮动子元素(如果有的话)的margin也都是相邻的。
当一个元素拥有的margin折叠了,并且它使用了清除操作,那么它的margin-top会和紧随其后的兄弟元素的相邻margin折叠,但结果是它的margin将无法和其块级父元素的margin-bottom折叠。
折叠操作是以padding、margin、border的值为基础的(即在浏览器解析所有这些值之后),折叠后的margin计算将覆盖已使用的不同margin的值。
博客等级:
博客积分:0
博客访问:84
关注人气:0
荣誉徽章:Fragment重叠问题引发的思考
Fragment重叠问题相信很多开发者都遇到个这个问题,也解决个这个问题,前段时间偶然发现,公司项目偶然出现了Fragment重叠的Bug,心里不由一紧,赶紧去stackoverflow搜索了一番,找到了好几种解决方案,最终问题是解决了,不过心里留下了很多疑问(为什么会出现重叠?为什么这么处理之后可以解决问题?这样写会不会引发其他问题?),带着我决定写个Demo去分析下每种解决方法的原理以及可能带来的负面影响。
一、问题重现
Demo是常见的用Fragment实现的Tab切换,拿了网上现成的Demo改了一下,先给个Fragment重叠的效果图:
在Fragment切换时,采用的show/hide的方式,原理是显示某个Fragment时,先把其他几个Fragment先隐藏掉:
private void setTabSelection(int index) {
clearSelection();
FragmentTransaction transaction = fragmentManager.beginTransaction();
hideFragments(transaction);
switch (index) {
messageImage.setImageResource(R.drawable.message_selected);
messageText.setTextColor(Color.WHITE);
if (messageFragment == null) {
messageFragment = new NormalListFragment();
transaction.add(R.id.content, messageFragment);
transaction.show(messageFragment);
contactsImage.setImageResource(R.drawable.contacts_selected);
contactsText.setTextColor(Color.WHITE);
if (contactsFragment == null) {
contactsFragment = new ContactsFragment();
transaction.add(R.id.content, contactsFragment);
transaction.show(contactsFragment);
newsImage.setImageResource(R.drawable.news_selected);
newsText.setTextColor(Color.WHITE);
if (newsFragment == null) {
newsFragment = new NewsFragment();
transaction.add(R.id.content, newsFragment);
transaction.show(newsFragment);
settingImage.setImageResource(R.drawable.setting_selected);
settingText.setTextColor(Color.WHITE);
if (settingFragment == null) {
settingFragment = new SettingFragment();
transaction.add(R.id.content, settingFragment);
transaction.show(settingFragment);
由于Fragment重叠问题是发生在某种特定的情况下,所以在常规环境下很难复现,所以需要在 手机开发者选项中把不保留活动这个选项打开,这样每次进入新的Activity,旧的Activity就会马上销毁。
假设现在处在第一个Tab 图片列表(NormalListFragment),然后点击某个Item进入详情页,由于不保留活动,Fragment所在的Activity会销毁掉。然后,我们从详情页返回到图片列表,Activity会重建,Fragment会重新绑定, 整个过程Activity和Fragment的生命周期方法调用Log如下:
06-18 21:35:36.479 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:36.479 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
06-18 21:35:36.893 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
onSaveInstanceState
Bundle[{android:viewHierarchyState=Bundle[{android:views={=android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.support.v7.widget.Toolbar$SavedState@bda98cc, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e}, android:focusedViewId=}], android:support:fragments=android.support.v4.app.FragmentManagerState@696715}]
06-18 21:35:36.893 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:36.893 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
06-18 21:35:36.910 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
onDestroyView
06-18 21:35:36.914 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:36.914 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:36.914 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
06-18 21:35:39.527 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.527 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.527 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
Bundle[{android:viewHierarchyState=Bundle[mParcelledData.dataSize=1512], android:support:fragments=android.support.v4.app.FragmentManagerState@e7e75b8}]
06-18 21:35:39.666 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
onCreateView
Bundle[{android:view_state={=AbsListView.SavedState{402bf7e selectedId=-4775808 firstId=-1 viewTop=0 position=0 height=1557 filter=null checkState=null}}}]
06-18 21:35:39.672 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
onActivityCreated
Bundle[{android:view_state={=AbsListView.SavedState{402bf7e selectedId=-4775808 firstId=-1 viewTop=0 position=0 height=1557 filter=null checkState=null}}}]
06-18 21:35:39.672 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.672 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.673 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
onCreateView
06-18 21:35:39.675 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
onActivityCreated
06-18 21:35:39.676 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.676 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.676 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
06-18 21:35:39.679 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
onRestoreInstanceState
Bundle[{android:viewHierarchyState=Bundle[{android:views={=android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.support.v7.widget.Toolbar$SavedState@80d4009=android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e}, android:focusedViewId=}], android:support:fragments=android.support.v4.app.FragmentManagerState@e7e75b8}]
06-18 21:35:39.680 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
06-18 21:35:39.680 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
06-18 21:35:39.680 /com.jx.androiddemos I/FragmentLearn: NormalListFragment
从上面的Log可以发现,重新创建Activity时,NormalListFragment每个周期方法都走了两遍。这意味着同时创建了两个NormalListFragment实例,这个两个NormalListFragment一个是我代码里面主动创建的,另外一个则是上次Activity异常销毁时保存的,因为恢复的这个Fragment没有拿到引用,所以无法去做操作的(隐藏显示),这意味着我切换到其他tab时,这个Fragment会一直显示,这正是Fragment重叠问题的根源所在。
下面从角度证实Activity在异常情况下销毁时,会保存Fragment。
从Log第三行打印的Bundle的值我们可以发现,Activity在异常销毁时会调用onSaveInstanceState方法,会默认保存一些数据,包括Fragment
06-18 21:35:36.893 /com.jx.androiddemos I/FragmentLearn: FragmentMainActivity
onSaveInstanceState
Bundle[{android:viewHierarchyState=Bundle[{android:views={=android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.support.v7.widget.Toolbar$SavedState@bda98cc, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e, =android.view.AbsSavedState$1@6962f3e}, android:focusedViewId=}], android:support:fragments=android.support.v4.app.FragmentManagerState@696715}]
这个我们从Activity源码中的onSaveInstanceState方法也能够确认:
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
getApplication().dispatchActivitySaveInstanceState(this, outState);
在onSaveInstanceState方法中,首先调用mFragments(FragmentManager)的saveAllState方法把Fragment数据保存到Parcelable 变量中,然后通过调用outState.putParcelable(FRAGMENTS_TAG, p);
保存到Bundle 中,FRAGMENTS_TAG这个常量
static final String FRAGMENTS_TAG = &android:support:fragments&;
也正是上面Log Bundle 数据中 键值对的一个键:
android:support:fragments=android.support.v4.app.FragmentManagerState@696715}
Activity异常销毁时保存Fragment已经可以确认,那么这个保存Fragment在重新创建Activity时,怎么恢复的了?这就需要研究Activity的onCreate方法了
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, &onCreate & + this + &: & + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp =
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
ActivityonCreate方法中和Fragment相关的应该是这几句:
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
mFragments.dispatchCreate();
当savedInstanceState 不为空时,意味着Activity上次销毁时保存了数据,会掉用FragmentManager 的 restoreAllState 方法,这个方法比较长,就不贴出来了,这个方法主要作用就是从savedInstanceState 把保存的Fragment都取出来,实例化,绑定到当前Activity。
通过上面的分析,对Fragment的保存和恢复应该有了比较清楚的理解,也找到的Fragment重叠的根源所在,那么下一步就是如何解决问题。
我在网上找到3中比较有代表性的解决方法,当然,实际可能有更多的解决方法,但每种方法的核心思想都是一样的,就是如何处理Activity异常销毁时保存的Fragment。
方法一、重写 onSaveInstanceState方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCustomVariable = savedInstanceState.getInt(&variable&, 0);
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt(&variable&, mCustomVariable);
这样重写之后,相当于不会调用Activity的onSaveInstanceState的方法保存系统默认数据,只保存自己需要的数据。Activity异常销毁时不会保存Fragment,当然也就不会再有重叠的问题出现。
不过这样处理是可能出现问题的,Activity的onSaveInstanceState方法不仅仅只是保存Fragment,还会保存获取焦点的View的状态,ActionBar,以及调用View的onSaveInstanceState 保存View的相关数据。
方法二、给每个Fragment根布局设置背景,拦截点击事件
android:background=&@android:color/white&
android:clickable=&true&
Fragment背景默认是透明的,所以我们能看到两个Fragment重叠在一起。当我们为每个Fragment添加背景之后,即使两个Fragment叠加在一起,我们也只看到一个。至于为什么要设置clickable=&true&,是因为两个Fragment叠加在一起,虽然我们只能看到上面那个,但是下面那个仍然能接收到事件。设置clickable=&true&时,上面的Fragment会拦截掉所有事件。
这样处理,能从视觉上解决问题,但是Activity异常销毁时,同一个Fragment同时出现两个实例的客观事实没有改变。有时你会发现Fragment中的某个网络接口明明应该只调用一次,Log却打印调用两次,其实是Fragment创建了两个实例。
方法三、用replace替代show/hide
用replace实现Tab切换的写法:
private void setTabSelection2(int index) {
clearSelection();
FragmentTransaction transaction = fragmentManager.beginTransaction();
switch (index) {
messageImage.setImageResource(R.drawable.message_selected);
messageText.setTextColor(Color.WHITE);
if (messageFragment == null) {
messageFragment = new NormalListFragment();
transaction.replace(R.id.content, messageFragment);
contactsImage.setImageResource(R.drawable.contacts_selected);
contactsText.setTextColor(Color.WHITE);
if (contactsFragment == null) {
contactsFragment = new ContactsFragment();
transaction.replace(R.id.content, contactsFragment);
newsImage.setImageResource(R.drawable.news_selected);
newsText.setTextColor(Color.WHITE);
if (newsFragment == null) {
newsFragment = new NewsFragment();
transaction.replace(R.id.content, newsFragment);
settingImage.setImageResource(R.drawable.setting_selected);
settingText.setTextColor(Color.WHITE);
if (settingFragment == null) {
settingFragment = new SettingFragment();
transaction.replace(R.id.content, settingFragment);
replace的做法是每次把Activity(准确的说是Activity添加Fragment的布局)的Fragment先全部移除掉,再添加新的Fragment,这样操作确保Activity的布局容器每次只会存在一个Fragment。当然不会出现重叠问题。
replace Fragment操作的源码,很容易看出是先移除容器包含的Fragment,然后再添加:
case OP_REPLACE: {
Fragment f = op.
if (mManager.mAdded != null) {
for (int i = 0; i & mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG,
&OP_REPLACE: adding=& + f + & old=& + old);
if (f == null || old.mContainerId == f.mContainerId) {
if (old == f) {
op.fragment = f =
if (op.removed == null) {
op.removed = new ArrayList();
op.removed.add(old);
old.mNextAnim = op.exitA
if (mAddToBackStack) {
old.mBackStackNesting += 1;
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, &Bump nesting of &
+ old + & to & + old.mBackStackNesting);
mManager.removeFragment(old, mTransition, mTransitionStyle);
if (f != null) {
f.mNextAnim = op.enterA
mManager.addFragment(f, false);
当然,这样处理后每次点击Tab之后,每个Fragment都要重新创建实例,走周期方法,加载数据。具体能不能这样做,还要看业务上允不允许每次重新加载数据。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'一年级重叠问题例题讲解_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
一年级重叠问题例题讲解
上传于||暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩2页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢重叠问题_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
上传于||文档简介
&&四​年​级​智​慧​广​场​课​件
大小:13.06MB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢

参考资料

 

随机推荐