添加第一个项目时回收查看项目动画崩溃

时间:2016-03-10 02:42:31

标签: android android-recyclerview

我正在开发一个小应用,用户可以在帖子上发布内容和评论。我在github上使用Instamaterial项目作为参考。

https://github.com/frogermcs/InstaMaterial/blob/master/app/src/main/java/io/github/froger/instamaterial/ui/activity/CommentsActivity.java

当用户发布新评论时,会有动画评论活动。一切都很酷......但是当我发布第一条评论时...应用程序崩溃并且没有显示评论动画(滚动到顶部)我花了一整天的时间尝试...但是找不到解决方案。 / p>

public class CommentsActivity extends AppCompatActivity implements SendCommentButton.OnSendClickListener {
    public static final String ARG_DRAWING_START_LOCATION = "arg_drawing_start_location";

    LinearLayout contentRoot;
    RecyclerView rvComments;
    LinearLayout llAddComment;
    EditText etComment;
    SendCommentButton btnSendComment;

    private CommentsAdapter commentsAdapter;
    private int drawingStartLocation;
    Toolbar toolbar;
    private int currentPostID;

    DatabaseHelper db;
    private PreferencesManager preferencesManager;
    ArrayList<PostResponse.PostComments> comments;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_comments);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        contentRoot = (LinearLayout) findViewById(R.id.contentRoot);
        rvComments = (RecyclerView) findViewById(R.id.rvComments);
        llAddComment = (LinearLayout) findViewById(R.id.llAddComment);
        etComment = (EditText) findViewById(R.id.etComment);
        btnSendComment = (SendCommentButton) findViewById(R.id.btnSendComment);

        preferencesManager = new PreferencesManager(CommentsActivity.this);
        db = new DatabaseHelper(CommentsActivity.this);

        setupToolbar();
        setupComments();
        setupSendCommentButton();

        drawingStartLocation = getIntent().getIntExtra(ARG_DRAWING_START_LOCATION, 0);
        if (savedInstanceState == null) {
            contentRoot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    contentRoot.getViewTreeObserver().removeOnPreDrawListener(this);
                    startIntroAnimation();
                    return true;
                }
            });
        }
    }

    protected void setupToolbar() {
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setDisplayShow
HomeEnabled(true);
            toolbar.setNavigationIcon(R.mipmap.ic_menu_cancel);
            toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onBackPressed();
                }
            });
        }
    }

    private void setupComments() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        rvComments.setLayoutManager(linearLayoutManager);
        rvComments.setHasFixedSize(true);
        currentPostID = getIntent().getIntExtra(PostResponse.KEY_ID, -1);
        comments = db.getCommentsByPostID(currentPostID);

        commentsAdapter = new CommentsAdapter(this, comments);
        rvComments.setAdapter(commentsAdapter);
        rvComments.setOverScrollMode(View.OVER_SCROLL_NEVER);
        rvComments.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    commentsAdapter.setAnimationsLocked(true);
                }
            }
        });
    }

    private void setupSendCommentButton() {
        btnSendComment.setOnSendClickListener(this);
    }

    private void startIntroAnimation() {
        ViewCompat.setElevation(getToolbar(), 0);
        contentRoot.setScaleY(0.1f);
        contentRoot.setPivotY(drawingStartLocation);
        llAddComment.setTranslationY(200);

        contentRoot.animate()
                .scaleY(1)
                .setDuration(200)
                .setInterpolator(new AccelerateInterpolator())
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        ViewCompat.setElevation(getToolbar(), Utils.dpToPx(8));
                        animateContent();
                    }
                })
                .start();
    }

    private void animateContent() {
        commentsAdapter.updateItems();
        llAddComment.animate().translationY(0)
                .setInterpolator(new DecelerateInterpolator())
                .setDuration(200)
                .start();
    }

    @Override
    public void onBackPressed() {
        ViewCompat.setElevation(getToolbar(), 0);

        contentRoot.postDelayed(new Runnable() {
            @Override
            public void run() {
                contentRoot.animate()
                        .translationY(Utils.getScreenHeight(CommentsActivity.this))
                        .setDuration(200)
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                CommentsActivity.super.onBackPressed();
                                overridePendingTransition(0, 0);
                            }
                        })
                        .start();
            }
        }, 100);
    }

    @Override
    public void onSendClickListener(View v) {
        if (validateComment()) {
            publishComment(etComment.getText().toString());

            PostResponse.PostComments newComment = new PostResponse().new PostComments();
            newComment.user_id = Integer.parseInt(preferencesManager.getUserID());
            newComment.comment = etComment.getText().toString();
            newComment.post_id = currentPostID;

            commentsAdapter.addItem(newComment);

            commentsAdapter.setAnimationsLocked(false);
            commentsAdapter.setDelayEnterAnimation(true);
            rvComments.smoothScrollBy(0, rvComments.getChildAt(0).getHeight() * commentsAdapter.getItemCount());

            etComment.setText(null);
            btnSendComment.setCurrentState(SendCommentButton.STATE_DONE);
        }
    }


    private boolean validateComment() {
        if (TextUtils.isEmpty(etComment.getText())) {
            btnSendComment.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake_error));
            return false;
        }

        return true;
    }

    private Toolbar getToolbar(){
        return toolbar;
    }



    /************************************************
     * VOLLEY CALLS TO PUBLISH A COMMENT
     * *****************************************************/
    private void publishComment(final String comment) {
       //Code here

    }

}

这是我的适配器

public class CommentsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    private int lastAnimatedPosition = -1;
    private int avatarSize;
    private int itemsCount = 0;


    private boolean animationsLocked = false;
    private boolean delayEnterAnimation = true;
    List<PostResponse.PostComments> mItems;

    public CommentsAdapter(Context context, List<PostResponse.PostComments> mItems) {
        this.context = context;
        this.mItems = mItems;
        avatarSize = context.getResources().getDimensionPixelSize(R.dimen.comment_avatar_size);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view = LayoutInflater.from(context).inflate(R.layout.item_comment, parent, false);
        return new CommentViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        runEnterAnimation(viewHolder.itemView, position);
        CommentViewHolder holder = (CommentViewHolder) viewHolder;
        holder.tvComment.setText(mItems.get(position).comment);

        Picasso.with(context)
                .load(R.drawable.user_profile)
                .centerCrop()
                .resize(avatarSize, avatarSize)
                .transform(new RoundedTransformation())
                .into(holder.ivUserAvatar);
    }

    private void runEnterAnimation(View view, int position) {
        if (animationsLocked) return;

        if (position > lastAnimatedPosition) {
            lastAnimatedPosition = position;
            view.setTranslationY(100);
            view.setAlpha(0.f);
            view.animate()
                    .translationY(0).alpha(1.f)
                    .setStartDelay(delayEnterAnimation ? 20 * (position) : 0)
                    .setInterpolator(new DecelerateInterpolator(2.f))
                    .setDuration(300)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            animationsLocked = true;
                        }
                    })
                    .start();
        }
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    public void updateItems() {
        notifyDataSetChanged();
    }

    public void addItem(PostResponse.PostComments newComment) {
        mItems.add(newComment);
        notifyItemInserted(mItems.size() - 1);
    }

    public void setAnimationsLocked(boolean animationsLocked) {
        this.animationsLocked = animationsLocked;
    }

    public void setDelayEnterAnimation(boolean delayEnterAnimation) {
        this.delayEnterAnimation = delayEnterAnimation;
    }

    public static class CommentViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.ivUserAvatar)
        ImageView ivUserAvatar;
        @Bind(R.id.tvComment)
        TextView tvComment;

        public CommentViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}

这是屏幕。

enter image description here 运作良好

enter image description here

第一个效果很好,但添加第一个注释永远不会有效。我得到了这个例外。

//这是例外

java.lang.NullPointerException
at com.test.abc.CommentsActivity.onSendClickListener(CommentsActivity.java:214)
at com.test.abc.views.SendCommentButton.onClick(SendCommentButton.java:80)
at android.view.View.performClick(View.java:4463)
at android.view.View$PerformClick.run(View.java:18770)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)

1 个答案:

答案 0 :(得分:0)

我知道你知道这是因为这条线 - (你在评论中告诉我)

rvComments.smoothScrollBy(0, rvComments.getChildAt(0).getHeight() *
          commentsAdapter.getItemCount());

但是你知道这是方法调用吗? rvComments.getChildAt(0).getHeight()

我的想法是,如果recyleView为空,则调用rvComments.getChildAt(0)是对空引用的引用,其为空 因此你NPE但是如果第一条评论已经添加,你就有了大小为1的列表,所以这一行rvComments.getChildAt(0).getHeight()会动态引用一个视图对象地址。

所以我猜你的解决方案是_since你知道它的首选高度查看或选择一个首选高度并硬编码并使用。或者,如果您真的坚持使用视图高度,请在前进之前检查列表大小。

...
  commentsAdapter.setAnimationsLocked(false);
  commentsAdapter.setDelayEnterAnimation(true);
  if(rvComments.getChildCount() > 0){
  //i guess you will have do rvComments.getChildAt(
  //rvComments.getChildCount()-1) rather than below
  rvComments.smoothScrollBy(0, rvComments.getChildAt(0).getHeight()
            * commentsAdapter.getItemCount());
  }else{
  //do something else or find something to do to get the height you want
  //and multiply. In short it means the first item.
...