Most of the code has been deleted from the source code and optimized into the new version. The new profile to: http://www.jianshu.com/p/6649f5239aef
Attention! Due to a version update, most of the code below no longer exists. The address of the project: https://github.com/xujiaji/DMView
# Outline, renderings
Introduction to the
Recently, the company’s project requirements require the implementation of bullet screen, which is the reason why I write this bullet screen demo. At present, the addition of bullets has been realized, and the simple encapsulation of the realization part. You can add a barrage by calling addBarrage(String Name, String MSG, String PIC) to pass the name, message and avatar address. The bullet screen is added from bottom to top again (default is 10 lines). After the total number of lines is filled, the lines that have been slid below will be filled first.
# thought
- Because RecyclerView can add item animation
- Each barrage is an object when initialized
isLive = true
Indicates active status - When the barrage ends
isLive = false
Represents inactive state (its value is assigned by end of animation listener) - When initializing ten shells behind the scenes (default ten lines), the loop checks
isLive
Whether it isfalse
If so, reset the content and then update the corresponding row.
implementation
1. First, how to animate
- Animation realize copy some classes of the project: https://github.com/wasabeef/recyclerview-animators
- The main animation parent is:
BaseItemAnimator
. - Then you create one
BaseItemAnimator
A subclass ofOverTotalLengthAnimator
, to achieve the animation effect from right to left, add the end of the animation listening, detailed code as follows:
package com.jiaji.dmview.recyclerview_item_anim;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
public class OverTotalLengthAnimator extends BaseItemAnimator {
@Override
protected void animateRemoveImpl(RecyclerView.ViewHolder holder) {
Log.e("TAG"."animateRemoveImpl...........................");
}
@Override
protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
Log.e("TAG"."preAnimateRemoveImpl...........................");
}
// After data is added, calling notifyItemInserted performs this method first, moving the Item header to the right edge
@Override
protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
Log.e("TAG"."preAnimateAddImpl...........................");
ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth());
}
// After preAnimateAddImpl is executed, this method calls startAnimation to animate from right to left
@Override
protected void animateAddImpl(RecyclerView.ViewHolder holder) {
Log.e("TAG"."animateAddImpl...........................");
startAnimation(holder);
}
// This method is called when an item is filled in, instead of being added, the previous barrage object is reused, and 'notifyItemChanged' is updated.
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
Log.e("TAG"."animateChange...........................");
// Since the item is hidden after the animation, the initialization should be displayed
newHolder.itemView.setVisibility(View.VISIBLE);
ViewCompat.setTranslationX(newHolder.itemView, newHolder.itemView.getRootView().getWidth());
startAnimation(newHolder);
return true;
}
// Start the animation, the entire process defaults to 8 seconds, when the animation ends call over to end the listening
private void startAnimation(final RecyclerView.ViewHolder holder) {
ViewCompat.animate(holder.itemView)
.translationX(-holder.itemView.getRootView().getWidth())
.setDuration(8000)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
Log.e("TAG"."onAnimationStart");
}
@Override
public void onAnimationEnd(View view) {
holder.itemView.setVisibility(View.GONE);
if(onAnimListener ! =null) {
onAnimListener.over();
}
Log.e("TAG"."onAnimationEnd");
}
@Override
public void onAnimationCancel(View view) {
Log.e("TAG"."onAnimationCancel");
}
})
.setStartDelay(getAddDelay(holder))
.start();
}
private OnAnimListener onAnimListener;
public void setOnAnimListener(OnAnimListener l) {
this.onAnimListener = l;
}
public interface OnAnimListener {
void over(a); }}Copy the code
2. Fill in data
- Initialize RecyclerView, vertical layout, add from bottom to top.
- Check whether it can continue to add (whether more than 10 lines), if not, the loop checks whether there is an item at the end of the animation, if there is, the item will be updated. If not, it will be added to the cache list. After each animation, it will continue to add the bullet-screen objects in the cache list.
- The previous implementation part was implemented in MainActivity, but later in order to facilitate the use of this later (I said in case one day), so it is written in
BarrageUtil
The inside. Take a look atBarrageUtil:
package com.jiaji.dmview.barrage;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.jiaji.dmview.recyclerview_item_anim.OverTotalLengthAnimator;
import java.util.ArrayList;
import java.util.List;
/** * Created by Administrator on 2016/6/7. */
public class BarrageUtil {
private Context context;/ / context
private RecyclerView rvBarrage;// Display the RecyclerView of bullets
private List<BarrageEntity> barrageList;// Fill the list of RecyclerView
private BarrageAdapter mBarrageAdapter;// Barrage adapter
private OverTotalLengthAnimator anim;// Live screen animation
private List<Integer> indexList;// Save the current barrage subscript
private List<BarrageEntity> barrageCache;// Cache a barrage object that cannot be added when the current screen is full
private LinearLayoutManager layoutManager;
public BarrageUtil(Context context, RecyclerView rvBarrage) {
this.context = context;
this.rvBarrage = rvBarrage;
init();
}
private void init(a) {
barrageList = new ArrayList<>();
barrageCache = new ArrayList<>();
indexList = new ArrayList<>();
layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true);
rvBarrage.setLayoutManager(layoutManager);
anim = new OverTotalLengthAnimator();
rvBarrage.setItemAnimator(anim);
mBarrageAdapter = new BarrageAdapter(barrageList);
rvBarrage.setAdapter(mBarrageAdapter);
// this is called when the animation ends
anim.setOnAnimListener(new OverTotalLengthAnimator.OnAnimListener() {
@Override
public void over(a) {
int index = indexList.get(0);// Get the index that ends this item
barrageList.get(index).over();// Get the object with the corresponding subscript, call the over() method on that object, and set isLive to false
indexList.remove(0);// Remove the subscript of the currently ending item from the movement subscript collection
if(! barrageCache.isEmpty()) {// Check whether the cached barrage list has a barrage
BarrageEntity b = barrageCache.get(0);
addBarrage(b.getPname(), b.getChatStr(), b.getPic());
barrageCache.remove(0); }}}); }public void addBarrage(String name, String msg, String pic) {
// Log.e("TAG", "visible_item_position = " + layoutManager.findFirstCompletelyVisibleItemPosition());
boolean isAdd = false;
if (barrageList.size() >= 10) {// If it is greater than 10, it will not be added
for (int i = 0, len = barrageList.size(); i < len; i++) {
BarrageEntity barrageEntity = barrageList.get(i);
if (barrageEntity.isLive()) {
continue;
}
if (rvBarrage.isComputingLayout()) {// notifyItemChanged cannot be changed when RecyclerView is computing, there is a certain probability of backout, so if the layout is computing, then jump out of the loop directly
isAdd = false;
break;
}
barrageEntity.change(name, msg, pic);
mBarrageAdapter.notifyItemChanged(i);
indexList.add(i);
isAdd = true;
break; }}else {
isAdd = true;
BarrageEntity barrageEntity = new BarrageEntity(name, msg, pic);
barrageList.add(barrageEntity);
mBarrageAdapter.notifyItemInserted(barrageList.size() - 1);
indexList.add(barrageList.size() - 1);
}
if(! isAdd) {// Add it to the bullet-screen cache list if not successfully added
barrageCache.add(newBarrageEntity(name, msg, pic)); }}}Copy the code
3. Barrage objects
package com.jiaji.dmview.barrage;
/**
* Created by Administrator on 2016/6/6.
*/
public class BarrageEntity {
private String pname;
private String chatStr;
private String pic;
private boolean isLive;
public BarrageEntity(String pname, String chatStr, String pic) {
this.pname = pname;
this.chatStr = chatStr;
this.pic = pic;
isLive = true;
}
public void change(String pname, String chatStr, String pic) {
this.pname = pname;
this.chatStr = chatStr;
this.pic = pic;
isLive = true;
}
public void over() {
isLive = false;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public String getChatStr() {
return chatStr;
}
public void setChatStr(String chatStr) {
this.chatStr = chatStr;
}
public String getPic() {
return pic;
}
public void setPic(String pic) { this.pic = pic; }}Copy the code
Use 4.
package com.jiaji.dmview;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.jiaji.dmview.barrage.BarrageUtil;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private BarrageUtil mBarrageUtil;
private RecyclerView rvBarrage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvBarrage = (RecyclerView) findViewById(R.id.rvBarrage);
mBarrageUtil = new BarrageUtil(this, rvBarrage);
}
public void onAddClick(View view) {
mBarrageUtil.addBarrage(new Date().toString(), "Chat messages..."."Https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=150237755, & FM = 116 & 4294706681 gp = 0. JPG"); }}Copy the code
So I wrote this demo. At that time, I thought of only ① custom layout to add sub-layout of bullet screen and then add animation. ② This demo is because I thought of RecyclerView to achieve such animation is easier to write and understand. I hope I can help you realize a bullet screen idea. Internet pictures load using the Glide: compile ‘com. Making. Bumptech. Glide: Glide: 3.7.0’
The demo address
https://github.com/xujiaji/DMView