scrollview嵌套下拉控件嵌套recyclerview(不动第三方原基础自定义)
相信会碰到很多类似的需求,一个列表控件,然后控件上方的一个头部需要自定义,这样就不好有时候也不能加在列表控件的头部了,那必须得嵌套一层scrollview了,没毛病,那么一般的列表控件都是有上拉下拉的操作,而且一般也是在 github 上找寻一个收藏量高的
来做为一个全局通用的上下拉控件,这里问题就来了,一般的 scrollview 嵌套 recyclerview 或者 listview 都毕竟容易解决,可是在加上一层上下拉控件呢?上下拉控件肯定会有它自己的触摸处理机制,这样你改起来也很麻烦,这种滑动触摸的问题最是难搞,也有的是scrollview,或许网上有一些第三方库已经有这个效果了,不过看了一些都是自定义的一些控件来解决的,而这里的虽然也是自定义,但是却是用的一些流行库在不动它原本的基础上自定义
嵌套 viewpage 嵌套 recyclerview 的,不过这种效果网上还是有些方案的,搜索material design效果也有一些现成的,不过 scrollview 嵌套 SwipeRefreshLayout 嵌套 recyclerview 或者 scrollview 嵌套 PtrClassicFrameLayout 嵌套 recyclerview 很少,我搜了好久没有满足我需求的,而且很多是自定义了 recyclerview 和下拉控件才解决的,这样的话它不是用的 github 原控件,可以说是自己写的,可项目里很多都是有固定的一套第三方库,你不能改,除非你是项目负责人,一开始就这样规定了,不然就得想办法去解决
还有一种网上的方案是退而求其次,用 NestedScrollView,不过这也有一些问题,就是下滑的时候对于侵入式的下拉方式有效果,可是对于非侵入刷新就不好使了,而且我个人也更喜欢非侵入刷新,所以花了些空闲的时间捣鼓了一个demo,解决了一个心头之患,下次遇到就能轻松的对待了,不用在去纠结用这个库是否会有问题了
一开始做的走了个误区,没有思考清楚,大致思路就是首先把下拉的控件禁止 setEnabled(false) ,然后scrollview拦截事件,判断滑动,超出了头部的距离就让子控件滑动,这是一个大致的思路,然后就开干了,可想法是美好的,现实是残酷的,并没有取得成功,而且还把自己的思路搅浑了
先看失败的效果图
咋一看好像没啥问题,而且简单,这还说这么多做什么,其实只是效果没有显示出来(显示不出来),这就尴尬了⊙﹏⊙‖∣
如果直接把上下拉控件包住头部其实没有问题,但是这样你下拉的时候在顶端显示效果,这样头部和直接加入到列表控件里有什么区别,所以重新创建了个类,从头再来,好好在理理思路,先从简单的开始,SwipeRefreshLayout 是android自带的下拉刷新库,而且是侵入式的下拉刷新,这样处理起来更简单,柿子挑软的捏了,这样都搞不定那就猝死在电脑边吧,结果肯定是成功了,先看效果图
this is scrollView其实就是一个固定的头部,测试用的,可以换成自己的,而且还能根据滑动添加动画,基本的需求都满足了,直接看代码,代码粗糙了点
package com.example.demo.test2; import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import android.widget.Toast; import com.example.demo.BaseActivity;
import com.example.demo.R; import butterknife.BindView; public class Test3Activity extends BaseActivity { @BindView(R.id.scrollView)
MyNestedScroll scrollView;
@BindView(R.id.tv_head)
TextView tv_head;
@BindView(R.id.layout)
SwipeRefreshLayout layout;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private boolean hasMeasured; @Override
protected int getLayoutId() {
return R.layout.activity_test3;
} @Override
protected void initView() {
recyclerView.setLayoutManager(new LinearLayoutManager(Test3Activity.this));
recyclerView.setAdapter(new ContentAdapter());
ViewTreeObserver vto = tv_head.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
if (hasMeasured == false) {
int height = tv_head.getMeasuredHeight();
scrollView.setHeadHeight(height);
hasMeasured = true;
}
return true;
}
});
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
boolean b = scrollView.getScrollY()==0;
layout.setEnabled(b);
}
});
//设置刷新时动画的颜色,可以设置4个
layout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_green_light);
layout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override
public void onRefresh() {
//正在刷新
// TODO Auto-generated method stub
new Handler().postDelayed(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
//刷新完成
layout.setRefreshing(false);
}
}, 500);
}
}); } class ContentAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(Test3Activity.this).inflate(R.layout.item_test, parent, false));
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ContentViewHolder viewHolder = (ContentViewHolder) holder;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(Test3Activity.this, ""+position, Toast.LENGTH_SHORT).show();
}
});
} @Override
public int getItemCount() {
return 15;
}
} class ContentViewHolder extends RecyclerView.ViewHolder { public ContentViewHolder(View itemView) {
super(itemView);
}
}
}
MainActivity
package com.example.demo.test2; import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView; /**
* Created by LiuZhen on 2017/6/8.
*/ public class MyNestedScroll extends ScrollView { private int headHeight = 300;//默认高度,一般动态设置
private int downY; public MyNestedScroll(Context context) {
super(context);
} public MyNestedScroll(Context context, AttributeSet attrs) {
super(context, attrs);
} public MyNestedScroll(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} @Override
public boolean onInterceptTouchEvent(MotionEvent e) {
int action = e.getAction();
int dis = getScrollY();
switch (action) {
case MotionEvent.ACTION_DOWN:
downY = (int) e.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) e.getRawY();
/**判断是向下滑动**/
if(downY-moveY>0){
if (dis < headHeight && dis >= 0){
return true;//滑动距离小于头部并且没有超出头部拦截事件,让本身去滑动
}else{
return false;//不拦截事件
}
}else{
}
} return super.onInterceptTouchEvent(e);
} public void setHeadHeight(int headHeight) {
this.headHeight = headHeight;
} }
MyNestedScroll
这个很简单,主要的逻辑也就一个方法里
然后在github上又找了个下拉库,收藏毕竟多
结果不行了,上滑一小段距离,然后在下拉,结果拉不动了,直接就显示了上拉效果,这显然不正常,问题一个一个来解决,肯定是有其它问题的,不过先把眼前的解决了才能下一步,要解决这个问题就得禁止 PtrClassicFrameLayout 的下拉了,问题的根源很有可能是我们用的上下拉控件的滑动刷新效果起冲突了,最好的办法肯定是直接禁止了,所以就给scrollview来个监听 onScrollChanged ,获取scrollview的scrolly,如果scrolly是0,就不禁止,因为在顶部了,不是0就禁止下拉操作,结果好了,可惜新的问题来了,上拉没反应了,因为被禁止了,所以需要判断滑动到了底部让下拉效果出现
于是有了这么两个判断,然后肯定还是有问题的,上拉效果没事了,下拉效果出事了,滑动到顶端的时候下拉效果直接出现了,这样头部都显示不出来了,而此时事件处于子列表控件,所以scrollview不好去监听了,只得在 recyclerView 上面下手了,需要监听滑动到顶部,然后禁止上下拉效果,交给scrollview滑动,让头部显示出来
可是这样一来发现还是那样,而调试发现的确触发了事件,可是为什么上下拉还是没有禁止呢,这样滑动不出头部,然后调试发现被下面的 scrollview 的 onScrollChanged 事件里覆盖了,又设置回去了,所以还得控制一下这里,让scrollview的监听不要覆盖上面的设置,这里只是下拉的时候才会用到,所以就有了dy这个全局参数,这样一来就ok了
package com.example.demo.test2; import android.os.Handler;
import android.support.v4.widget.NestedScrollView;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast; import com.example.demo.BaseActivity;
import com.example.demo.R;
import com.example.demo.test2.MyRecyclerView; import butterknife.BindView;
import in.srain.cube.views.ptr.PtrClassicFrameLayout;
import in.srain.cube.views.ptr.PtrDefaultHandler2;
import in.srain.cube.views.ptr.PtrFrameLayout; public class Test2Activity extends BaseActivity { @BindView(R.id.scrollView)
MyNestedScroll scrollView;
@BindView(R.id.tv_head)
TextView tv_head;
@BindView(R.id.layout)
PtrClassicFrameLayout layout;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private boolean hasMeasured;
int height,dy; @Override
protected int getLayoutId() {
return R.layout.activity_test2;
} @Override
protected void initView() {
final LinearLayoutManager manager = new LinearLayoutManager(Test2Activity.this);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(new ContentAdapter());
ViewTreeObserver vto = tv_head.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
if (hasMeasured == false) {
height = tv_head.getMeasuredHeight();
scrollView.setHeadHeight(height);//设置头部的高度
hasMeasured = true;
}
return true;
}
}); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // int visibleItemCount = manager.getChildCount();
// int totalItemCount = manager.getItemCount();
int pastVisiblesItems = manager.findFirstVisibleItemPosition();
Test2Activity.this.dy = dy;
//小于0表示下拉滑动,下拉到顶端则禁止子控件刷新,让scrollview滑动,头部完全显示后才能下拉,这里只做下滑到顶部时禁止立刻刷新,让scrollview滑动
if ( pastVisiblesItems == 0 && dy < 0) {
Log.e("onScrolled","dy "+dy);
layout.setEnabled(false);
}
}
});
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
//滑动的距离超出头部,让列表控件自己滑动,dy大于0是上滑操作,这里只做滑动超出头部后交给子列表滑动
boolean b = scrollView.getScrollY()==0;//上拉一段距离后下拉,结果直接下拉效果出现了,滑动失效
//解决上拉滑动到底部后让上拉效果有用
if (scrollView != null && scrollView.getMeasuredHeight() <= scrollView.getScrollY()+height && dy >= 0) {
b = true;
// Log.e("Changed","true ");
}
layout.setEnabled(b);
Log.e("Changed",""+b+" - scrollView.getScrollY "+scrollView.getScrollY());
}
});
layout.setLastUpdateTimeRelateObject(this);
layout.setPtrHandler(new PtrDefaultHandler2() { @Override
public void onLoadMoreBegin(PtrFrameLayout frame) {
updateData();
} @Override
public void onRefreshBegin(PtrFrameLayout frame) {
updateData();
} @Override
public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
return super.checkCanDoLoadMore(frame, recyclerView, footer);
} @Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return super.checkCanDoRefresh(frame, recyclerView, header);
}
}); layout.postDelayed(new Runnable() {
@Override
public void run() {
// mPtrFrame.autoRefresh();
}
}, 100); } protected void updateData() { layout.postDelayed(new Runnable() {
@Override
public void run() {
layout.refreshComplete();
}
}, 1000);
} class ContentAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(Test2Activity.this).inflate(R.layout.item_test, parent, false));
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ContentViewHolder viewHolder = (ContentViewHolder) holder;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(Test2Activity.this, ""+position, Toast.LENGTH_SHORT).show();
}
});
} @Override
public int getItemCount() {
return 15;
}
} class ContentViewHolder extends RecyclerView.ViewHolder { public ContentViewHolder(View itemView) {
super(itemView);
}
}
}
MainActivity
侵入式的下拉刷新的确麻烦很多,但是好在自己也都解决了,而有了这两种方案不敢说每个第三方库都能通用,但是大部分都可以通用,只要懂得了其中的原理,自己稍加修改也行,毕竟第三方库太多了,每个库都有它自己的自定义,所以还是要根据独特的情况去修改
网上有些第三方的,但是也都是人家自定义重新做的,并不能完美的和第三方库结合,所以很多时候与其苦苦找寻不如自己慢慢摸索,这样无论是用别人的还是自己定义都更加的了解原理,而且这种效果是很频繁出现在项目中的,所以自己必须得搞懂才行,不然你下次种会遇到它的
前面命名有点乱,在这里从新把代码都贴一下,以免搞混
侵入式和非侵入式
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import android.widget.Toast; import com.example.demo.BaseActivity;
import com.example.demo.R; import butterknife.BindView;
import in.srain.cube.views.ptr.PtrClassicFrameLayout;
import in.srain.cube.views.ptr.PtrDefaultHandler2;
import in.srain.cube.views.ptr.PtrFrameLayout; public class PtrClassicFrameScrollViewActivity extends BaseActivity { @BindView(R.id.scrollView)
MyNestedScroll scrollView;
@BindView(R.id.tv_head)
TextView tv_head;
@BindView(R.id.layout)
PtrClassicFrameLayout layout;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private boolean hasMeasured;
int height,dy; @Override
protected int getLayoutId() {
return R.layout.activity_ptr;
} @Override
protected void initView() {
final LinearLayoutManager manager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(new ContentAdapter());
ViewTreeObserver vto = tv_head.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
if (hasMeasured == false) {
height = tv_head.getMeasuredHeight();
scrollView.setHeadHeight(height);//设置头部的高度
hasMeasured = true;
}
return true;
}
}); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // int visibleItemCount = manager.getChildCount();
// int totalItemCount = manager.getItemCount();
int pastVisiblesItems = manager.findFirstVisibleItemPosition();
PtrClassicFrameScrollViewActivity.this.dy = dy;
//小于0表示下拉滑动,下拉到顶端则禁止子控件刷新,让scrollview滑动,头部完全显示后才能下拉,这里只做下滑到顶部时禁止立刻刷新,让scrollview滑动
if ( pastVisiblesItems == 0 && dy < 0) {
Log.e("onScrolled","dy "+dy);
layout.setEnabled(false);
}
}
});
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
//滑动的距离超出头部,让列表控件自己滑动,dy大于0是上滑操作,这里只做滑动超出头部后交给子列表滑动
boolean b = scrollView.getScrollY()==0;//上拉一段距离后下拉,结果直接下拉效果出现了,滑动失效
//解决上拉滑动到底部后让上拉效果有用
if (scrollView != null && scrollView.getMeasuredHeight() <= scrollView.getScrollY()+height && dy >= 0) {
b = true;
// Log.e("Changed","true ");
}
layout.setEnabled(b);
// Log.e("Changed",""+b+" - scrollView.getScrollY "+scrollView.getScrollY());
}
});
layout.setLastUpdateTimeRelateObject(this);
layout.setPtrHandler(new PtrDefaultHandler2() { @Override
public void onLoadMoreBegin(PtrFrameLayout frame) {
updateData();
} @Override
public void onRefreshBegin(PtrFrameLayout frame) {
updateData();
} @Override
public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
return super.checkCanDoLoadMore(frame, recyclerView, footer);
} @Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return super.checkCanDoRefresh(frame, recyclerView, header);
}
}); layout.postDelayed(new Runnable() {
@Override
public void run() {
// mPtrFrame.autoRefresh();
}
}, 100); } protected void updateData() { layout.postDelayed(new Runnable() {
@Override
public void run() {
layout.refreshComplete();
}
}, 1000);
} class ContentAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(PtrClassicFrameScrollViewActivity.this).inflate(R.layout.item_test, parent, false));
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ContentViewHolder viewHolder = (ContentViewHolder) holder;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, ""+position, Toast.LENGTH_SHORT).show();
}
});
} @Override
public int getItemCount() {
return 15;
}
} class ContentViewHolder extends RecyclerView.ViewHolder { public ContentViewHolder(View itemView) {
super(itemView);
}
}
}
PtrClassicFrameScrollViewActivity
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.example.demo.MyNestedScroll
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <TextView
android:id="@+id/tv_head"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#ffffff"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:text="this is scrollView" /> <in.srain.cube.views.ptr.PtrClassicFrameLayout
xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="600dp"
android:background="#ffffff"
cube_ptr:ptr_duration_to_close_either="1000"
cube_ptr:ptr_keep_header_when_refresh="true"
cube_ptr:ptr_pull_to_fresh="false"
cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
cube_ptr:ptr_resistance="1.7"> <android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </in.srain.cube.views.ptr.PtrClassicFrameLayout>
</LinearLayout>
</com.example.demo.MyNestedScroll> </FrameLayout>
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import android.widget.Toast; import com.example.demo.BaseActivity;
import com.example.demo.R; import butterknife.BindView; public class SwipeRefreshScrollViewActivity extends BaseActivity { @BindView(R.id.scrollView)
MyNestedScroll scrollView;
@BindView(R.id.tv_head)
TextView tv_head;
@BindView(R.id.layout)
SwipeRefreshLayout layout;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private boolean hasMeasured; @Override
protected int getLayoutId() {
return R.layout.activity_swipe;
} @Override
protected void initView() {
recyclerView.setLayoutManager(new LinearLayoutManager(SwipeRefreshScrollViewActivity.this));
recyclerView.setAdapter(new ContentAdapter());
ViewTreeObserver vto = tv_head.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
if (hasMeasured == false) {
int height = tv_head.getMeasuredHeight();
scrollView.setHeadHeight(height);
hasMeasured = true;
}
return true;
}
});
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
boolean b = scrollView.getScrollY()==0;
layout.setEnabled(b);
}
});
//设置刷新时动画的颜色,可以设置4个
layout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_green_light);
layout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override
public void onRefresh() {
//正在刷新
// TODO Auto-generated method stub
new Handler().postDelayed(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
//刷新完成
layout.setRefreshing(false);
}
}, 500);
}
}); } class ContentAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(SwipeRefreshScrollViewActivity.this).inflate(R.layout.item_test, parent, false));
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ContentViewHolder viewHolder = (ContentViewHolder) holder;
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(SwipeRefreshScrollViewActivity.this, ""+position, Toast.LENGTH_SHORT).show();
}
});
} @Override
public int getItemCount() {
return 15;
}
} class ContentViewHolder extends RecyclerView.ViewHolder { public ContentViewHolder(View itemView) {
super(itemView);
}
}
}
SwipeRefreshScrollViewActivity
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.example.demo.MyNestedScroll
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <TextView
android:id="@+id/tv_head"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#ffffff"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:text="this is scrollView" /> <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="800dp"
android:background="#ffffff"> <android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
</com.example.demo.MyNestedScroll> </android.support.constraint.ConstraintLayout>
github下载地址:https://github.com/1024477951/ScrollPullView
scrollview嵌套下拉控件嵌套recyclerview(不动第三方原基础自定义)的更多相关文章
- DevExpress控件GridView挂下拉控件无法对上值
下拉控件使用RepositoryItemLookUpEdit,加入如下事件进行处理. repositoryItemLookUpEdit1.CustomDisplayText += new DevExp ...
- 一不小心写了个bootstrap风格下拉控件 JqueryUI + bootstrap
受够了EasyUI的封闭,Bootstrap虽然华丽但是功能太渣,闲着无聊写个下拉控件玩玩吧,不喜勿喷哈... 第一步:先设计下我的下拉控件的样子 1.既然是bootstrap风格的,我想应该是这样的 ...
- 基于bootstrap的multiple-select下拉控件使用
multiple-select是一款优秀的下拉菜单控件,能够支持单选和多选. 详细参考文档: JS组件系列——两种bootstrap multiselect组件大比拼 multiple-select ...
- 下拉控件jQuery插件
由于后端开发需要一个下拉控件,能输入,能选择,于是自己写了一个 ;(function($,window,document,undefined){ function Select(el,opt){ th ...
- 解决easyUI下拉控件无法触发onkeydown事件
实现在combotree下拉控件中按Backspace键清除combotree选中的值 下面的代码无法获取到键盘事件 <input class="easyui-combotree&qu ...
- 使用谷歌提供的SwipeRefreshLayout下拉控件,并自定义实现下拉加载的功能
package com.loaderman.swiperefreshdemo; import android.os.Bundle; import android.os.Handler; import ...
- SDI在自定义的工具栏上添加下拉控件
0.首先到自己的工具条上新建一个控件,并命名新ID 1.拷贝FlatComboBox.h和FlatComboBox.cpp到工程目录下 2.建立新类 class CTrackerToolBar : p ...
- 下拉框、下拉控件之Select2。自动补全的使用
参考链接: 参考一:https://blog.csdn.net/weixin_36146275/article/details/79336158 参考二:https://www.cnblogs.com ...
- java 下拉控件 转自 http://www.cnblogs.com/lhb25/p/form-enhanced-with-javascript-three.html
表单元素让人爱恨交加.作为网页最重要的组成部分,表单几乎无处不在,从简单的邮件订阅.登陆注册到复杂的需要多页填写的信息提交功能,表单都让开发者花费了大量的时间和精力去处理,以期实现好用又漂亮的表单功能 ...
随机推荐
- 在nuget上发布自己的程序集教程
前期准备 [1]注册nuget官网账号:注册地址:https://www.nuget.org/ [2]下载Nuget.exe文件:下载地址:https://www.nuget.org/downloa ...
- 学习python的第一天
2019.4.25自我总结 一.Typora 关于用Typora 自我感觉良好,基本快捷键也比较简单,ps:还是要多用用 二.编程 1.编程语言 是用来定义计算机程序的形式语言.它是一种被标准化的交流 ...
- 新手学习WEB前端流程以及学习中常见的误区
学习web前端编程技术肯定是以就业拿到高薪工作为主要目的的,可是高薪不会那么轻易拿到,这是一个最简单的道理.没有付出就没有回报,在整个学习web前端编程技术的过程中,你需要付出时间.精力.金钱.废话不 ...
- html基础复习
1.标签选择器 div{} 2.类选择器 .one class="one" 3.id选择器(定义+调用) #one{} id="one" ...
- 24, CSS 构造超链接
1. 超链接边框 2. 派生超链接 3. 属性选择器超链接 4. 动态超链接 5. 图像翻转超链接 6. CSS 工具提示 1.给链接加上边框 A:link { Color: #f00; Text-d ...
- Oracle数据库升级注意事项
1 备份配置参数 数据库升级前的配置参数要备份,如PGA大小 这样数据库升级后还可以升级前的配置,而不至于使用安装升级时的默认配置 2 检查版本兼容 确认数据库升级后是否对生产环境上的代码有影响,如果 ...
- Vagrant 构建 Linux 开发环境
Vagrant 是一个简单易用的部署工具,用英文说应该是 Orchestration Tool .它能帮助开发人员迅速的构建一个开发环境,帮助测试人员构建测试环境, Vagrant 基于 Ruby 开 ...
- Markdown工具Atom及基本语法
下载使用 访问atom.io下载Atom 这里下载的是1.33.1版本 好用的插件包 点击File->Settings->Packages,可以安装指定的插件包. markdown-img ...
- render与vue组件和注册
<template> <div class="about"> <h1>This is an about page</h1> < ...
- CTF取证方法大汇总,建议收藏!
站在巨人的肩头才会看见更远的世界,这是一篇来自技术牛人的神总结,运用多年实战经验总结的CTF取证方法,全面细致,通俗易懂,掌握了这个技能定会让你在CTF路上少走很多弯路,不看真的会后悔! 本篇文章大约 ...