Menu
Woocommerce Menu

ScrollView中嵌入ListView常见问题和解决方案,播放器的封装

0 Comment


边缓存边播放的视频器封装

Android程序员面试宝典

自己写了一个自定义的ViewGroup的流式布局,但是调用addView方法添加xml中的View的时候报错:

模仿原生的提供的视频播放器VideoView,封装一个仿微信的视频播放器。

问题:

The specified child already has a parent.You must call removeView() on the child's parent first."

原生的VideoView,为了解耦和方便定制,把MediaPlayer的播放逻辑和UI界面展示及操作相关的逻辑分离。加入边播放边缓存的功能,引入AndroidVideoCache缓存库。

ScrollView内部嵌套的ListView,数据显示不完整。

二话不说,点源码看一下,顺着addView的流程,最后走到了addViewInner()这个方法,看下代码

微信的播放界面如下:

原因:

 private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) { if (mTransition != null) { // Don't prevent other add transitions from completing, but cancel remove // transitions to let them complete the process before we add to the container mTransition.cancel(LayoutTransition.DISAPPEARING); } if (child.getParent() != null) { //这里抛出了我遇到的错误的异常 throw new IllegalStateException("The specified child already has a parent. " + "You must call removeView() on the child's parent first."); } if (mTransition != null) { mTransition.addChild(this, child); } if (!checkLayoutParams { params = generateLayoutParams; } if (preventRequestLayout) { child.mLayoutParams = params; } else { child.setLayoutParams; } if (index < 0) { index = mChildrenCount; } addInArray(child, index); // tell our children if (preventRequestLayout) { child.assignParent; } else { child.mParent = this; } if (child.hasFocus { requestChildFocus(child, child.findFocus; } AttachInfo ai = mAttachInfo; if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) { boolean lastKeepOn = ai.mKeepScreenOn; ai.mKeepScreenOn = false; child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK)); if (ai.mKeepScreenOn) { needGlobalAttributesUpdate; } ai.mKeepScreenOn = lastKeepOn; } if (child.isLayoutDirectionInherited { child.resetRtlProperties(); } dispatchViewAdded; if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; } if (child.hasTransientState { childHasTransientStateChanged(child, true); } if (child.getVisibility() != View.GONE) { notifySubtreeAccessibilityStateChangedIfNeeded(); } if (mTransientIndices != null) { final int transientCount = mTransientIndices.size(); for (int i = 0; i < transientCount; ++i) { final int oldIndex = mTransientIndices.get; if (index <= oldIndex) { mTransientIndices.set(i, oldIndex + 1); } } } if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) { notifyChildOfDragStart; } }

图片 1微信的播放界面.png

ScrollView的滑动事件的消费处理以及ListView控件的高度设定问题

从注释中可以看到代码哪里错了,瞬间明白,其实,在Android中,一个View只能属于一个特定的ViewGroup,我自定义了一个ViewGroup,然后又addView()加载xml中的一个view的时候,这个View的外层布局是一个LinearLayout。到了addInnerView的时候。进入if条件语句,抛出异常,崩溃。

界面的设计封装

解决方案:

图片 2

该方法缺陷:

  1. Adapter中getView方法返回的View的必须由LinearLayout组成,如果使用其他的布局如RelativeLayout,在调用listItem.measure;时就会抛异常

  2. 把整个需要放在ScrollView中的内容,统统放在ListView中,原ListView上方的数据和下方数据,都作为现ListView的一个itemView,和原ListView中的单条数据是平级的关系。一个单独的ListView就可以了

我们只需要自定义一个类继承自LinearLayout,为其加上对BaseAdapter的适配

图片 3

自定义一个类继承自ListView,通过重写其onMeasure方法,达到对ScrollView适配的效果

图片 4

方案一:

优点:是不用对使用的控件做任何修改,只需要使用一个现成的方法就好了。

缺点:最大的限制是ListView的item只能由LinearLayout这一个布局组成,对于一些复杂的布局就不适用了

方案二:

优点:是完全解决了ScrollView嵌套ListView的问题,同时代码较少,你甚至可以直接使用LinearLayout,而在Activity中手动为LinearLayout添加子项控件,不过需要注意的是,在添加前需要调用其removeAllViews的方法,否则会抛出异常。

缺点:不能向ListView那样可以使用ViewHolder结构,在加载大量子项时会费很多时间在findViewById中。

方案三:

优点:是布局文件设计简单、Activity中的代码也很少。

  • 欢迎关注微信公众号、长期为您推荐优秀博文、开源项目、视频

  • 微信公众号名称:Android干货程序员

  • 图片 5

 if (child.getParent() != null) { //这里抛出了我遇到的错误的异常 throw new IllegalStateException("The specified child already has a parent. " + "You must call removeView() on the child's parent first."); }

图片 6界面.png

把View的父ViewGroup解除关系,再在自己的ViewGroup添加就好。

通过FrameLayout 叠上两层 UI Layout + TextureView。

 if (childView != null) { ViewGroup parentViewGroup = (ViewGroup) childView.getParent(); if (parentViewGroup != null ) { parentViewGroup.removeView(childView); } }
标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图