LinearLayout addView不起作用

时间:2016-05-17 08:25:46

标签: android

我把addView()放在onTouchEvent()方法中,但它不起作用。问题是什么?当我将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&&currentHeaderHeight<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();
}}

3 个答案:

答案 0 :(得分:2)

如果您确定添加了视图但看不到,请确保已设置LinearLayout的方向。默认方向是水平的,可能视图将添加到现有视图的一侧,并且不可见。您可以使用以下方法将其设置为垂直方向:

myLayout.setOrientation(LinearLayout.VERTICAL);

答案 1 :(得分:2)

将线性布局放在滚动视图中。

答案 2 :(得分:1)

您需要实施 View.OnTouchListener 。只需修改您的代码,如下所示:

invalidate();
  

尝试在addView();

之后调用{{1}}