我把addView()放在onTouchEvent()方法中,但它不起作用。问题是什么?当我将addView放在构造函数中时,它可以正常工作。
setOrientation(LinearLayout.VERTICAL)已添加到构造函数中 这是代码:
public class RecyclerViewRefresh extends LinearLayout{
private static final String LOG_TAG=RecyclerViewRefresh.class.getSimpleName();
private static final int INVALID_POINTER=-1;
//Default offset in dips from the top of the view to where the progress
//spinner should stop
private static final int DEFAULT_CIRCLE_TARGET=64;
private static final float DRAG_RATE=.5f;
private Context context;
private View headerView,footerView,thisView;
private View mTarget; //the target of the gesture
private ImageView arrowIv;
private TextView refreshTv;
private ProgressBar progressBar,footerProgressBar;
private OnPullToRefresh refreshListener=null;
private OnDragToLoad loadListener=null;
float startY=0;
private int headerHeight=0,currentHeaderHeight=0,currentFooterHeight=0;
private boolean mReturningToStart;
private boolean mRefreshing=false;
private boolean mNestedScrollInProgress;
private int mCurrentTargetOffsetTop;
protected int mOriginalOffsetTop;
private boolean mIsBeingDragged;
private boolean mIsBeingPullUp;
private boolean isAddFooter=false;
private int mActivePointerId=INVALID_POINTER;
private float mInitailDownY;
private int mTouchSlop;
private float mTotalDragDistance=-1;
private float mInitialMotionY;
private float mSpinnerFinalOffset;
private boolean updateHeader=true;
private Handler handler=new Handler();
private Timer timer;
public RecyclerViewRefresh(Context context) {
super(context);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context)
{
this.setOrientation(LinearLayout.VERTICAL);
this.context=context;
thisView=this;
mTouchSlop= ViewConfiguration.get(context).getScaledTouchSlop();
headerView=LayoutInflater.from(context).inflate(R.layout.header_layout,null);
footerView=LayoutInflater.from(context).inflate(R.layout.footer_layout,null);
measureView(headerView);
measureView(footerView);
arrowIv=(ImageView)headerView.findViewById(R.id.arrow);
refreshTv=(TextView)headerView.findViewById(R.id.tip);
progressBar=(ProgressBar)headerView.findViewById(R.id.progress);
headerHeight=headerView.getMeasuredHeight();
currentHeaderHeight=headerHeight;
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
headerView.getMeasuredHeight());
this.addView(headerView,lp);
setTopHeader(headerHeight);
final DisplayMetrics metrics=getResources().getDisplayMetrics();
mSpinnerFinalOffset=DEFAULT_CIRCLE_TARGET*metrics.density;
mTotalDragDistance=mSpinnerFinalOffset;
}
/**
* 通知父布局,占用的宽,高;
*
* @param view
*/
private void measureView(View view) {
ViewGroup.LayoutParams p = view.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
int height;
int tempHeight = p.height;
if (tempHeight > 0) {
height = MeasureSpec.makeMeasureSpec(tempHeight,
MeasureSpec.EXACTLY);
} else {
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
view.measure(width, height);
}
private void setTopHeader(int height)
{
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
{
this.setY(-height);
}else{
LayoutParams lp=new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height);
lp.topMargin=-height;
this.setLayoutParams(lp);
}
headerView.invalidate();
}
/**
* Set the listener to be notified when a refresh is triggered via the
* pull gesture.
* @param listener
*/
public void setOnPullToRefresh(OnPullToRefresh listener)
{
this.refreshListener=listener;
}
/**
* Set the listener to be notified when a load is triggered via the
* drag gesture
* @param listener
*/
public void setOnDragToLoad(OnDragToLoad listener)
{
this.loadListener=listener;
}
private void ensureTarget(){
if(mTarget==null){
for(int i=0;i<getChildCount();i++)
{
View child=getChildAt(i);
if(child instanceof RecyclerView)
{
mTarget=child;
break;
}
}
}
}
/**
* @return Whether it is possible for the child view of this layout to
* scroll up.Override this if the child view is a custom view.
*/
public boolean canChildScrollUp(){
if(mTarget==null)
{
ensureTarget();
}
if(Build.VERSION.SDK_INT<14)
{
if(mTarget instanceof AbsListView)
{
final AbsListView absListView=(AbsListView)mTarget;
return absListView.getChildCount()>0
&&(absListView.getFirstVisiblePosition()>0
||absListView.getChildAt(0).getTop()<absListView.getPaddingTop());
}else{
return ViewCompat.canScrollVertically(mTarget,-1)|| mTarget.getScrollY()>0;
}
}else{
return ViewCompat.canScrollVertically(mTarget,-1);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ensureTarget();
final int action=MotionEventCompat.getActionMasked(ev);
if(mReturningToStart && action == MotionEvent.ACTION_DOWN){
mReturningToStart = false;
}
if(!isEnabled() || mReturningToStart || (canChildScrollUp()&&!ifLastItemVisible())
||mRefreshing || mNestedScrollInProgress){
return false;
}
switch (action){
case MotionEvent.ACTION_DOWN:
setTargetOffsetTopAndBottom(mOriginalOffsetTop-headerView.getTop(),true);
mActivePointerId=MotionEventCompat.getPointerId(ev,0);
mIsBeingDragged=false;
mIsBeingPullUp=false;
final float initialDownY=getMotionEventY(ev,mActivePointerId);
if(initialDownY==-1){
return false;
}
mInitailDownY=initialDownY;
updateHeader=true;
break;
case MotionEvent.ACTION_MOVE:
if(mActivePointerId==INVALID_POINTER){
Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
return false;
}
final float y=getMotionEventY(ev,mActivePointerId);
if(y==-1){
return false;
}
final float yDiff=y-mInitailDownY;
if(yDiff>mTouchSlop && !mIsBeingDragged){
mInitialMotionY=mInitailDownY+mTouchSlop;
mIsBeingDragged=true;
}
if(yDiff<-mTouchSlop&&!mIsBeingPullUp&&ifLastItemVisible()&&!isAddFooter)
{
Log.d(LOG_TAG,"pullUp");
mInitialMotionY=mInitailDownY+mTouchSlop;
mIsBeingPullUp=true;
return true;
}
if(ifLastItemVisible()&&yDiff>mTouchSlop)
{
isAddFooter=false;
return false;
}
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDragged=false;
mActivePointerId=INVALID_POINTER;
break;
}
return mIsBeingDragged;
}
private boolean ifLastItemVisible()
{
final RecyclerView recyclerView=(RecyclerView)mTarget;
LinearLayoutManager manager=(LinearLayoutManager)recyclerView.getLayoutManager();
if((manager.findLastVisibleItemPosition()+1)==manager.getItemCount())
{
return true;
}
return false;
}
private float getMotionEventY(MotionEvent ev,int activePointerId){
final int index=MotionEventCompat.findPointerIndex(ev,activePointerId);
if(index<0){
return -1;
}
return MotionEventCompat.getY(ev,index);
}
private void setTargetOffsetTopAndBottom(int offset,boolean requiresUpdate){
if(currentHeaderHeight>-5)
{
currentHeaderHeight-=offset;
this.setY(-currentHeaderHeight);
mCurrentTargetOffsetTop=this.getTop();
if(requiresUpdate && Build.VERSION.SDK_INT<11){
invalidate();
}
if(currentHeaderHeight<0)
{
if(updateHeader){
updateHeader=false;
refreshTv.setText(getResources().getText(R.string.releasetorefresh));
RotateAnimation animation=new RotateAnimation(0,180,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(800);
animation.setFillAfter(true);
arrowIv.startAnimation(animation);
}
Log.d(LOG_TAG,"top="+this.getY());
}
}
}
private void onSecondaryPointerUp(MotionEvent ev){
final int pointerIndex=MotionEventCompat.getActionIndex(ev);
final int pointerId=MotionEventCompat.getPointerId(ev,pointerIndex);
if(pointerId==mActivePointerId){
//This was our active pointer going up. Choose a new
//active pointer and adjust accordingly.
final int newPointerIndex=pointerIndex==0?1:0;
mActivePointerId=MotionEventCompat.getPointerId(ev,newPointerIndex);
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
final int action=MotionEventCompat.getActionMasked(event);
int pointerIndex=-1;
if(mReturningToStart&&action==MotionEvent.ACTION_DOWN){
mReturningToStart=false;
}
if(!isEnabled() || mReturningToStart
|| (canChildScrollUp()&&!ifLastItemVisible()) || mNestedScrollInProgress){
//Fail fast if we're not in a state where a swipe is possible
return false;
}
switch(action){
case MotionEvent.ACTION_DOWN:
mActivePointerId=MotionEventCompat.getPointerId(event,0);
mIsBeingDragged=false;
break;
case MotionEvent.ACTION_MOVE:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
final float overscrollTop=(y-mInitialMotionY)*DRAG_RATE;
Log.d(LOG_TAG,"move overscroll="+overscrollTop+" y="+y+" mInitialMotionY="+mInitialMotionY+" mIsBeingDragged="+(mIsBeingDragged?"true":"false")
+" mIsBeingPullUp="+(mIsBeingPullUp?"true":"false"));
if(mIsBeingDragged){
if(overscrollTop>0){
moveSpinner(overscrollTop);
}else{
return false;
}
}
if(mIsBeingPullUp&&!isAddFooter){
Log.d(LOG_TAG,"isAddFooter="+(isAddFooter?"true":"false"));
if(overscrollTop<0&&!isAddFooter){
isAddFooter=true;
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
footerView.getMeasuredHeight());
Log.d(LOG_TAG,"addFooterView height="+footerView.getMeasuredHeight()
+" childcount="+this.getChildCount());
if(this.getChildCount()==2)
{
this.addView(footerView,lp);
footerView.setVisibility(View.VISIBLE);
invalidate();
}
Log.d(LOG_TAG,"childcount="+this.getChildCount());
}else{
return false;
}
}
break;
}
case MotionEventCompat.ACTION_POINTER_DOWN:{
pointerIndex=MotionEventCompat.getActionIndex(event);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
return false;
}
mActivePointerId=MotionEventCompat.getPointerId(event,pointerIndex);
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
break;
case MotionEvent.ACTION_UP:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
mIsBeingDragged=false;
finishSpinner();
mActivePointerId=INVALID_POINTER;
return false;
}
case MotionEvent.ACTION_CANCEL:
return false;
}
return true;
}
private void moveSpinner(float overscrollTop){
float originalDragPercent=overscrollTop/mTotalDragDistance;
float dragPercent=Math.min(1f,Math.abs(originalDragPercent));
float adjustedPercent=(float)Math.max(dragPercent-.4,0)*5/3;
float extraOS=Math.abs(overscrollTop)-mTotalDragDistance;
float slingshotDist=mSpinnerFinalOffset;
float tensionSlingshotPercent=Math.max(0,Math.min(extraOS,slingshotDist*2)/slingshotDist);
float tensionPercent=(float)((tensionSlingshotPercent/4)-Math.pow(
(tensionSlingshotPercent/4),2))*2f;
float extraMove=(slingshotDist)*tensionPercent*2;
int targetY=mOriginalOffsetTop+(int)((slingshotDist*dragPercent)+extraMove);
setTargetOffsetTopAndBottom(targetY-mCurrentTargetOffsetTop,true);
}
private void finishSpinner(){
if(currentHeaderHeight<0){
setRefreshing(true,true);
}else{
//cancel refresh
mRefreshing=false;
animateOffsetToStartPosition();
}
}
private void setRefreshing(boolean refreshing,final boolean notify)
{
if(mRefreshing!=refreshing){
ensureTarget();
mRefreshing=refreshing;
if(mRefreshing){
refreshListener.onRefresh();
arrowIv.setVisibility(View.GONE);
arrowIv.clearAnimation();
progressBar.setVisibility(View.VISIBLE);
}else{
arrowIv.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
refreshTv.setText(getResources().getText(R.string.afterrefresh));
animateOffsetToStartPosition();
}
}
}
public void setRefreshing(boolean refreshing){
if(!refreshing){
setRefreshing(refreshing,false);
}
}
private void animateOffsetToStartPosition(){
refreshTv.setText(getResources().getText(R.string.pulltorefresh));
arrowIv.clearAnimation();
if(timer==null&¤tHeaderHeight<headerHeight)
{
timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
if(currentHeaderHeight<headerHeight)
{
currentHeaderHeight+=5;
thisView.setY(-currentHeaderHeight);
mCurrentTargetOffsetTop = headerView.getTop();
if ( Build.VERSION.SDK_INT < 11) {
invalidate();
}
}else{
if(timer!=null)
{
arrowIv.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
timer.cancel();
timer=null;
}
}
}
});
}
},10,10);
}
}
/**
* Classes that wish to be notified when the pull gesture correctly
* triggers a refresh should implement this interface.
*/
public interface OnPullToRefresh{
public void onRefresh();
}
/**
* Classes that wish to be notified when the drag gesture correctly
* triggers a load should implement this interface.
*/
public interface OnDragToLoad{
public void onLoad();
}}
答案 0 :(得分:2)
如果您确定添加了视图但看不到,请确保已设置LinearLayout的方向。默认方向是水平的,可能视图将添加到现有视图的一侧,并且不可见。您可以使用以下方法将其设置为垂直方向:
myLayout.setOrientation(LinearLayout.VERTICAL);
答案 1 :(得分:2)
将线性布局放在滚动视图中。
答案 2 :(得分:1)
您需要实施 View.OnTouchListener 。只需修改您的代码,如下所示:
invalidate();
尝试在addView();
之后调用{{1}}