在IOS中,在过度滑动时,整体布局会进行偏移,松手后,会出现回弹效果
安卓中则大多数控件都没有这种功能,在这里,可以自定义一个ViewGroup
容器,针对该容器包裹的内容,可以进行过度滚动
为了实现,我 们需要进行接下来的处理
一、 创建ViewGroup布局
因为是要实现一个容器,因此需要自定义一个ViewGroup
,然后重载构造函数,这里定义该控件名字为:OverScrollContainer
/**
* Created on 2018/10/10 15:31
* function : 包裹容器;用于在view外部形成一个可以over-scroll的视图
*
*
* 只能有一个子view,否则,视图将加载错乱
* 仅支持纵轴过度滑动
*
* @author mnlin
*/
class OverScrollContainer : ViewGroup {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
}
如代码注释描述,该控件只支持纵轴
方向的滚动,只能有一个Child
。
二、 定义可使用的属性
在初始阶段,我们定义的属性会简单一些,只要可以满足基本的需要就好。
纵轴滚动有两种方式:向上、向下
那么对应的,我们需要暴露以下的基本属性:
<!--弹性 布局 距离-->
<declare-styleable name="OverScrollContainer">
<!--弹性滚动顶部的距离-->
<attr name="overScrollDimen_top" format="dimension"/>
<!--弹性滚动底部的距离-->
<attr name="overScrollDimen_bottom" format="dimension"/>
<!--超出滚动部分的颜色-->
<attr name="overScroll_bg_color" format="color"/>
<!--顶部过度滚动效果-->
<attr name="enable_top" format="boolean"/>
<!--底部过度滚动效果-->
<attr name="enable_bottom" format="boolean"/>
</declare-styleable>
这样,在使用时,就可以根据说明,轻易的配置控件显示效果
接下来我们需要考虑,怎么来使用这些属性;
毋庸置疑的是,这些属性都将作用于OverScrollContainer
控件,如果我们定义的是View控件
,而非ViewGroup
,那就没的商量,只要把这些 属性在xml布局中,<OverScrollContainer>
标签上配置一下就好。但对于一个ViewGroup来说,为了使用这些属性,一般都会定义自己的LayoutParams
,通过LayoutParams
来处理效果的显示
就像FrameLayout
一样:
/**
* Per-child layout information for layouts that support margins.
* See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
* for a list of all child view attributes that this class supports.
*
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
/**
* Value for {@link #gravity} indicating that a gravity has not been
* explicitly specified.
*/
public static final int UNSPECIFIED_GRAVITY = -1;
/**
* The gravity to apply with the View to which these layout parameters
* are associated.
* <p>
* The default value is {@link #UNSPECIFIED_GRAVITY}, which is treated
* by FrameLayout as {@code Gravity.TOP | Gravity.START}.
*
* @see android.view.Gravity
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
public int gravity = UNSPECIFIED_GRAVITY;
public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
super(c, attrs);
final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity, UNSPECIFIED_GRAVITY);
a.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
/**
* Creates a new set of layout parameters with the specified width, height
* and weight.
*
* @param width the width, either {@link #MATCH_PARENT},
* {@link #WRAP_CONTENT} or a fixed size in pixels
* @param height the height, either {@link #MATCH_PARENT},
* {@link #WRAP_CONTENT} or a fixed size in pixels
* @param gravity the gravity
*
* @see android.view.Gravity
*/
public LayoutParams(int width, int height, int gravity) {
super(width, height);
this.gravity = gravity;
}
public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
super(source);
}
/**
* Copy constructor. Clones the width, height, margin values, and
* gravity of the source.
*
* @param source The layout params to copy from.
*/
public LayoutParams(@NonNull LayoutParams source) {
super(source);
this.gravity = source.gravity;
}
}
这样一来,在FrameLayout
布局中,子View
只需要指定gravity
,就可以调整自己在父布局中的显示效果。
更重要的是,使用LayoutParams
的话,将来想要添加一些新的属性时,会方便的多。
我们仿照FrameLayout
,来实现OverScrollContainer
对应的LayoutParams
:
/**
* 自定义layoutParams,便于实现自定义的属性
*/
class LayoutParams : ViewGroup.MarginLayoutParams {
/**
* over-scroll的距离
*/
var overScrollDimenTop: Int = 96
var overScrollDimenBottom: Int = 96
/**
* 是否可以回弹
*/
var topEnable = true
var bottomEnable = true
/**
* 滚动后留存的背景颜色
*/
var bgColor = 0
var bgDrawable: Drawable = ColorDrawable(Color.TRANSPARENT)
constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {
val a = c.obtainStyledAttributes(attrs, R.styleable.OverScrollContainer)
overScrollDimenTop = a.getDimensionPixelSize(R.styleable.OverScrollContainer_overScrollDimen_top, 96)
overScrollDimenBottom = a.getDimensionPixelSize(R.styleable.OverScrollContainer_overScrollDimen_bottom, 96)
topEnable = a.getBoolean(R.styleable.OverScrollContainer_enable_top, true)
bottomEnable = a.getBoolean(R.styleable.OverScrollContainer_enable_bottom, true)
bgColor = a.getColor(R.styleable.OverScrollContainer_overScroll_bg_color, 0)
bgDrawable = ColorDrawable(bgColor)
a.recycle()
}
constructor(width: Int, height: Int) : super(width, height)
constructor(source: ViewGroup.LayoutParams) : super(source)
constructor(source: ViewGroup.MarginLayoutParams) : super(source)
constructor(source: OverScrollContainer.LayoutParams) : super(source) {
overScrollDimenTop = source.overScrollDimenTop
overScrollDimenBottom = source.overScrollDimenBottom
topEnable = source.topEnable
bottomEnable = source.bottomEnable
bgColor = source.bgColor
bgDrawable = source.bgDrawable
}
}
然后在自定义的 ViewGroup
中,重写 LayoutParams
的生成方法:
override fun generateDefaultLayoutParams(): OverScrollContainer.LayoutParams {
return OverScrollContainer.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
override fun generateLayoutParams(attrs: AttributeSet): OverScrollContainer.LayoutParams {
return OverScrollContainer.LayoutParams(context, attrs)
}
override fun generateLayoutParams(lp: ViewGroup.LayoutParams): ViewGroup.LayoutParams {
if (lp is OverScrollContainer.LayoutParams) {
return OverScrollContainer.LayoutParams(lp)
} else if (lp is ViewGroup.MarginLayoutParams) {
return OverScrollContainer.LayoutParams(lp)
}
return OverScrollContainer.LayoutParams(lp)
}
三、自定义 measure 处理
前面也说了,在初期,我们规定该布局只能管理一个可滚动的View(或者ViewGroup),因此,measure
时,只需要看一下第一个布局的宽高,然后让自身宽高等于子布局的宽高即可:
/**
* 测量子view高度
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (childCount == 1) {
//自身尺寸遵循唯一子布局的尺寸
val child = getChildAt(0)
val lp = child.layoutParams as LayoutParams
measureChild(child, widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(child.measuredWidth + lp.marginStart + lp.marginEnd + paddingStart + paddingEnd,
child.measuredHeight + lp.topMargin + lp.bottomMargin + paddingTop + paddingBottom)
} else {
setMeasuredDimension(0, 0)
}
}
这里设定自身的宽为:child.measuredWidth + lp.marginStart + lp.marginEnd + paddingStart + paddingEnd
设定自身高为:child.measuredHeight + lp.topMargin + lp.bottomMargin + paddingTop + paddingBottom
当子布局不存在或者超过一个,那么自身宽高皆为 0 ,将不会显示出来
四、自定义 layout 处理
在 measure
之后,我们确定一下唯一子view
的上下左右位置。
/**
* 规范子view的坐标位置
*/
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
val childCount = childCount
if (childCount == 1) {
val child = getChildAt(0)
val lp = child.layoutParams as LayoutParams
val left_p = lp.marginStart + paddingStart
val top_p = lp.topMargin + paddingTop
val right_p = left_p + child.measuredWidth
val bottom_p = top_p + child.measuredHeight
child.layout(left_p, top_p, right_p, bottom_p)
} else {
//当子布局不存在,或者超过一个,则不进行正常布局
//setFrame(0,0,0,0);
}
}
同样的,我们也考虑了padding
与margin
对布局造成的影响
五、自定义 draw 处理
在处理draw
流程时,需要考虑ScrollX
与ScrollY
对布局造成的影响,同时,需要绘制出滚动显示的背景,以及自定义添加的一些文字提示,因此首先定义一些局部变量:
/**
* 手指按下的坐标
* 当前的坐标
*/
private var down_y: Float = 0.toFloat()
private var current_y: Float = 0.toFloat()
/**
* 控制器
*/
private var controlListener: ControlInterceptListener? = null
/**
* 文字画笔
*/
private var singlePaint = TextPaint().also {
it.textSize = 28.toFloat()
it.color = Color.RED
}
/**
* 平滑滚动控制
*/
private val singleScroller = Scroller(this.context)
然后根据 scrollY
来绘制背景,scrollY
实际是指该方法的返回值:
/**
* Return the scrolled top position of this view. This is the top edge of
* the displayed part of your view. You do not need to draw any pixels above
* it, since those are outside of the frame of your view on screen.
*
* @return The top edge of the displayed part of your view, in pixels.
*/
public final int getScrollY() {
return mScrollY;
}
根据view的内容滚动原理:
scrollY
小于0时,表示向下滑动手指,顶部出现滚动区域;scrollY
大于0时,表示向上滑动手指;
/**
* 添加头部的填充内容
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//存在滚动效果时,进行绘制
if (scrollY != 0) {
(getChildAt(0)?.layoutParams as LayoutParams?)?.let { lp ->
//上部过度滚动效果
if (scrollY < 0) {
//绘制默认顶部图形
lp.bgDrawable.run {
setBounds(lp.marginStart + paddingStart, -lp.overScrollDimenTop, width - lp.marginEnd - paddingEnd, lp.topMargin + paddingTop)
draw(canvas)
}
//绘制文字,保证滑动时,跟随在最顶部
"你是最棒的!!!".let {
singlePaint.color = Color.argb((-1.0 * scrollY / lp.overScrollDimenTop * 0xFF).toInt(), 0xFF, 0x00, 0x00)
canvas.drawText(it, (width - singlePaint.measureText(it)) / 2, scrollY - singlePaint.fontMetrics.top, singlePaint)
}
}
//下部过度滚动效果
if (scrollY > 0) {
//绘制默认顶部图形
lp.bgDrawable.run {
setBounds(lp.marginStart + paddingStart, height - lp.bottomMargin - paddingBottom, width - lp.marginEnd - paddingEnd, height + lp.overScrollDimenBottom)
draw(canvas)
}
//绘制文字,保证滑动时,跟随在最顶部
"我是最棒的!!!".let {
singlePaint.color = Color.argb((1.0 * scrollY / lp.overScrollDimenBottom * 0xFF).toInt(), 0xFF, 0x00, 0x00)
canvas.drawText(it, (width - singlePaint.measureText(it)) / 2, height + scrollY - singlePaint.fontMetrics.bottom, singlePaint)
}
}
}
}
}
六、拦截事件,获取坐标信息
在上面的代码中,我们使用了 画笔 singlePaint
等对象,还有一些变量如:手指按压位置坐标
,当前手指坐标
等数据,在触发滑动操作时,是需要考虑在内的,因此需要不断更新。
当然,还有点击事件的处理,现在不妨考虑的简单一些:所有发生在 OverScrollContainer
上的滑动事件,都会被拦截进行处理。
为了灵活性,我们还向外部提供一个接口,可以控制是否可以拦截事件,不设置监听器的的话默认的话,默认事件会被OverScrollContainer
拦截
/**
* 判断是否可以拦截事件
*/
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
down_y = ev.y
}
}
//在滚动时,指定所有父布局不能拦截自身的点击事件
return if (ev.action == MotionEvent.ACTION_MOVE
&& childCount != 0
&& (getChildAt(0).layoutParams as LayoutParams).let { it.bottomEnable or it.topEnable }
&& controlListener?.canIntercept(ev) != false) {
var temp_parent = parent ?: null
while (temp_parent != null) {
parent.requestDisallowInterceptTouchEvent(true)
temp_parent = temp_parent.parent ?: null
}
true
} else {
false
}
}
/**
* 处理滑动逻辑
*/
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_MOVE -> {
current_y = event.y
val result = (down_y - current_y).toInt()
(getChildAt(0)?.layoutParams as LayoutParams?)?.let { lp ->
//判断当前是否可以滑动
when {
result < 0 && lp.topEnable && lp.overScrollDimenTop > 0 -> lp.overScrollDimenTop
result > 0 && lp.bottomEnable && lp.overScrollDimenBottom > 0 -> lp.overScrollDimenBottom
else -> null
}?.let {
scrollTo(0, if (Math.abs(result) > it) result / Math.abs(result) * it else result)
}
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
//回归原来位置,平滑滚动
singleScroller.startScroll(scrollX, scrollY, -scrollX, -scrollY, 500)
invalidate()
}
}
return true
}
然后重写computeScroll
方法,保证可以缓慢滑动:
/**
* smooth-scroll
*/
override fun computeScroll() {
super.computeScroll()
//判断动画是否完成
if (singleScroller.computeScrollOffset()) {
scrollTo(singleScroller.currX, singleScroller.currY)
//通知重绘
invalidate()
}
}
ControlInterceptListener
接口代码为:
/**
* function : 控制OverScrollContainer是否可以拦截事件
*
* Created on 2018/10/15 17:44
* @author mnlin
*/
public interface ControlInterceptListener {
/**
* 是否可以拦截
*
* @return true表示可以(但实际情况可能并不会去拦截)
*/
default boolean canIntercept(MotionEvent me){
return true;
}
}
这样一来,就可以完成一个简单的回弹效果,效果如下:
在这基础上,还可以添加一些可以修改字体颜色的属性,或者屏蔽水平竖直滚动的比例来判断,当前滚动发生的方向等等
七、布局文件与类文件
最后贴出使用的xml布局,以及源码
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.example.test.tv.test_view.wrapper.OverScrollContainer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="20dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="16dp"
android:background="#5500FFFF"
android:paddingBottom="14dp"
android:paddingEnd="10dp"
android:paddingStart="16dp"
android:paddingTop="20dp">
<ImageView
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_margin="10dp"
android:gravity="center"
android:src="#22FF4081"
android:text="456123"
android:textSize="20sp"
app:enable_bottom="true"
app:enable_top="true"
app:overScrollDimen_bottom="48dp"
app:overScrollDimen_top="48dp"
app:overScroll_bg_color="#55aa00aa"/>
</com.example.test.tv.test_view.wrapper.OverScrollContainer>
</LinearLayout>
</ScrollView>
OverScrollContainer
源码:
/**
* function : 包裹容器;用于在view外部形成一个可以over-scroll的视图
*
*
* 只能有一个子view,否则,视图将加载错乱
* 仅支持纵轴过度滑动
*/
class OverScrollContainer : ViewGroup {
/**
* 手指按下的坐标
* 当前的坐标
*/
private var down_y: Float = 0.toFloat()
private var current_y: Float = 0.toFloat()
/**
* 控制器
*/
private var controlListener: ControlInterceptListener? = null
/**
* 文字画笔
*/
private var singlePaint = TextPaint().also {
it.textSize = 28.toFloat()
it.color = Color.RED
}
/**
* 平滑滚动控制
*/
private val singleScroller = Scroller(this.context)
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/**
* 判断是否可以拦截事件
*/
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
down_y = ev.y
}
}
//在滚动时,指定所有父布局不能拦截自身的点击事件
return if (ev.action == MotionEvent.ACTION_MOVE
&& childCount != 0
&& (getChildAt(0).layoutParams as LayoutParams).let { it.bottomEnable or it.topEnable }
&& controlListener?.canIntercept(ev) != false) {
var temp_parent = parent ?: null
while (temp_parent != null) {
parent.requestDisallowInterceptTouchEvent(true)
temp_parent = temp_parent.parent ?: null
}
true
} else {
false
}
}
/**
* 处理滑动逻辑
*/
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_MOVE -> {
current_y = event.y
val result = (down_y - current_y).toInt()
(getChildAt(0)?.layoutParams as LayoutParams?)?.let { lp ->
//判断当前是否可以滑动
when {
result < 0 && lp.topEnable && lp.overScrollDimenTop > 0 -> lp.overScrollDimenTop
result > 0 && lp.bottomEnable && lp.overScrollDimenBottom > 0 -> lp.overScrollDimenBottom
else -> null
}?.let {
scrollTo(0, if (Math.abs(result) > it) result / Math.abs(result) * it else result)
}
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
//回归原来位置,平滑滚动
singleScroller.startScroll(scrollX, scrollY, -scrollX, -scrollY, 500)
invalidate()
}
}
return true
}
/**
* smooth-scroll
*/
override fun computeScroll() {
super.computeScroll()
//判断动画是否完成
if (singleScroller.computeScrollOffset()) {
scrollTo(singleScroller.currX, singleScroller.currY)
//通知重绘
invalidate()
}
}
/**
* 测量子view高度
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (childCount == 1) {
//自身尺寸遵循唯一子布局的尺寸
val child = getChildAt(0)
val lp = child.layoutParams as LayoutParams
measureChild(child, widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(child.measuredWidth + lp.marginStart + lp.marginEnd + paddingStart + paddingEnd,
child.measuredHeight + lp.topMargin + lp.bottomMargin + paddingTop + paddingBottom)
} else {
setMeasuredDimension(0, 0)
}
}
/**
* 规范子view的坐标位置
*/
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
val childCount = childCount
if (childCount == 1) {
val child = getChildAt(0)
val lp = child.layoutParams as LayoutParams
val left_p = lp.marginStart + paddingStart
val top_p = lp.topMargin + paddingTop
val right_p = left_p + child.measuredWidth
val bottom_p = top_p + child.measuredHeight
child.layout(left_p, top_p, right_p, bottom_p)
} else {
//当子布局不存在,或者超过一个,则不进行正常布局
//setFrame(0,0,0,0);
}
}
/**
* 添加头部的填充内容
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//存在滚动效果时,进行绘制
if (scrollY != 0) {
(getChildAt(0)?.layoutParams as LayoutParams?)?.let { lp ->
//上部过度滚动效果
if (scrollY < 0) {
//绘制默认顶部图形
lp.bgDrawable.run {
setBounds(lp.marginStart + paddingStart, -lp.overScrollDimenTop, width - lp.marginEnd - paddingEnd, lp.topMargin + paddingTop)
draw(canvas)
}
//绘制文字,保证滑动时,跟随在最顶部
"你是最棒的!!!".let {
singlePaint.color = Color.argb((-1.0 * scrollY / lp.overScrollDimenTop * 0xFF).toInt(), 0xFF, 0x00, 0x00)
canvas.drawText(it, (width - singlePaint.measureText(it)) / 2, scrollY - singlePaint.fontMetrics.top, singlePaint)
}
}
//下部过度滚动效果
if (scrollY > 0) {
//绘制默认顶部图形
lp.bgDrawable.run {
setBounds(lp.marginStart + paddingStart, height - lp.bottomMargin - paddingBottom, width - lp.marginEnd - paddingEnd, height + lp.overScrollDimenBottom)
draw(canvas)
}
//绘制文字,保证滑动时,跟随在最顶部
"我是最棒的!!!".let {
singlePaint.color = Color.argb((1.0 * scrollY / lp.overScrollDimenBottom * 0xFF).toInt(), 0xFF, 0x00, 0x00)
canvas.drawText(it, (width - singlePaint.measureText(it)) / 2, height + scrollY - singlePaint.fontMetrics.bottom, singlePaint)
}
}
}
}
}
/**
* 添加控制器,可以根据子布局的状态来控制OverScrollContainer是否可以滑动
*/
fun setControlInterceptListener(listener: ControlInterceptListener?) {
this.controlListener = listener
}
override fun generateDefaultLayoutParams(): OverScrollContainer.LayoutParams {
return OverScrollContainer.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
override fun generateLayoutParams(attrs: AttributeSet): OverScrollContainer.LayoutParams {
return OverScrollContainer.LayoutParams(context, attrs)
}
override fun generateLayoutParams(lp: ViewGroup.LayoutParams): ViewGroup.LayoutParams {
if (lp is OverScrollContainer.LayoutParams) {
return OverScrollContainer.LayoutParams(lp)
} else if (lp is ViewGroup.MarginLayoutParams) {
return OverScrollContainer.LayoutParams(lp)
}
return OverScrollContainer.LayoutParams(lp)
}
/**
* 自定义layoutParams,便于实现自定义的属性
*/
class LayoutParams : ViewGroup.MarginLayoutParams {
/**
* over-scroll的距离
*/
var overScrollDimenTop: Int = 96
var overScrollDimenBottom: Int = 96
/**
* 是否可以回弹
*/
var topEnable = true
var bottomEnable = true
/**
* 滚动后留存的背景颜色
*/
var bgColor = 0
var bgDrawable: Drawable = ColorDrawable(Color.TRANSPARENT)
constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {
val a = c.obtainStyledAttributes(attrs, R.styleable.OverScrollContainer)
overScrollDimenTop = a.getDimensionPixelSize(R.styleable.OverScrollContainer_overScrollDimen_top, 96)
overScrollDimenBottom = a.getDimensionPixelSize(R.styleable.OverScrollContainer_overScrollDimen_bottom, 96)
topEnable = a.getBoolean(R.styleable.OverScrollContainer_enable_top, true)
bottomEnable = a.getBoolean(R.styleable.OverScrollContainer_enable_bottom, true)
bgColor = a.getColor(R.styleable.OverScrollContainer_overScroll_bg_color, 0)
bgDrawable = ColorDrawable(bgColor)
a.recycle()
}
constructor(width: Int, height: Int) : super(width, height)
constructor(source: ViewGroup.LayoutParams) : super(source)
constructor(source: ViewGroup.MarginLayoutParams) : super(source)
constructor(source: OverScrollContainer.LayoutParams) : super(source) {
overScrollDimenTop = source.overScrollDimenTop
overScrollDimenBottom = source.overScrollDimenBottom
topEnable = source.topEnable
bottomEnable = source.bottomEnable
bgColor = source.bgColor
bgDrawable = source.bgDrawable
}
}
}