編輯:關於Android編程
RecyclerView改變數據:
跟RemoveDuration、MoveDuration、AddDuration一樣,ChangeDuration默認的動畫屬性
都是通過阿爾法通道淡入淡出,下面的效果依然是我們作為練習自己修改的。
MyAdapter.java:
package com.iwanghang.recyclerviewdemo; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; /** * ViewHolder 減少不必要的調用findViewById,不必要每次都重新加載控件布局 */ public class MyAdapter extends RecyclerView.AdapterMyItemAnimator.java:implements View.OnClickListener { private Context context; private List list; // 接口回調 private OnMyItemClickListener listener; private RecyclerView recyclerView; // 接口回調 setter getter // public OnMyItemClickListener getOnMyItemClickListener() { // return listener; // } public void setOnMyItemClickListener(OnMyItemClickListener listener) { this.listener = listener; } // 當它連接到一個RecyclerView調用的方法 @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); this.recyclerView = recyclerView; } // 當它與RecyclerView解除連接調用的方法 @Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); this.recyclerView = null; } public MyAdapter(Context context, List list) { this.context = context; this.list = list; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item,parent,false); view.setOnClickListener(this); return new MyViewHolder(view); } // 上面 view.setOnClickListener(this);的點擊實現方法 @Override public void onClick(View view) { if (recyclerView != null && listener != null) { int position = recyclerView.getChildAdapterPosition(view); listener.onMyItemClick(recyclerView,view,position,list.get(position)); // 接口回調 } } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.item_text.setText(list.get(position)); } @Override public int getItemCount() { return list.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder{ private TextView item_text; public MyViewHolder(View itemView) { super(itemView); item_text = (TextView) itemView.findViewById(R.id.item_text); } } // public Context getContext() { // return context; // } // public void setContext(Context context) { // this.context = context; // } // public List getList() { // return list; // } // public void setList(List list) { // this.list = list; // } // 接口回調 public interface OnMyItemClickListener{ void onMyItemClick(RecyclerView parent, View view, int position, String data); } // 刪除數據 public void remove(int position){ list.remove(position); //notifyDataSetChanged();// 提醒list刷新,沒有動畫效果 notifyItemRemoved(position); // 提醒item刪除指定數據,這裡有RecyclerView的動畫效果 } // 添加數據 public void add(int position, String data){ list.add(position, data); notifyItemInserted(position); } // 改變數據 public void change(int position, String data){ list.remove(position); list.add(position, data); notifyItemChanged(position); } }
package com.iwanghang.recyclerviewdemo; import android.support.annotation.NonNull; import android.support.v4.animation.AnimatorCompatHelper; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListener; import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.SimpleItemAnimator; import android.view.View; import java.util.ArrayList; import java.util.List; /** * 直接復制了DefaultItemAnimator修改為MyItemAnimator,來實現 * 我們自己對動畫的需要求 * 在MainActivity中,也不再實例化DefaultItemAnimator,而是 * 實例化MyItemAnimator */ public class MyItemAnimator extends SimpleItemAnimator { private static final boolean DEBUG = false; private ArrayListmPendingRemovals = new ArrayList<>(); private ArrayList mPendingAdditions = new ArrayList<>(); private ArrayList mPendingMoves = new ArrayList<>(); private ArrayList mPendingChanges = new ArrayList<>(); ArrayList> mAdditionsList = new ArrayList<>(); ArrayList> mMovesList = new ArrayList<>(); ArrayList> mChangesList = new ArrayList<>(); ArrayList mAddAnimations = new ArrayList<>(); ArrayList mMoveAnimations = new ArrayList<>(); ArrayList mRemoveAnimations = new ArrayList<>(); ArrayList mChangeAnimations = new ArrayList<>(); private static class MoveInfo { public ViewHolder holder; public int fromX, fromY, toX, toY; MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { this.holder = holder; this.fromX = fromX; this.fromY = fromY; this.toX = toX; this.toY = toY; } } private static class ChangeInfo { public ViewHolder oldHolder, newHolder; public int fromX, fromY, toX, toY; private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { this.oldHolder = oldHolder; this.newHolder = newHolder; } ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { this(oldHolder, newHolder); this.fromX = fromX; this.fromY = fromY; this.toX = toX; this.toY = toY; } @Override public String toString() { return "ChangeInfo{" + "oldHolder=" + oldHolder + ", newHolder=" + newHolder + ", fromX=" + fromX + ", fromY=" + fromY + ", toX=" + toX + ", toY=" + toY + '}'; } } @Override public void runPendingAnimations() { boolean removalsPending = !mPendingRemovals.isEmpty(); boolean movesPending = !mPendingMoves.isEmpty(); boolean changesPending = !mPendingChanges.isEmpty(); boolean additionsPending = !mPendingAdditions.isEmpty(); if (!removalsPending && !movesPending && !additionsPending && !changesPending) { // nothing to animate return; } // First, remove stuff for (ViewHolder holder : mPendingRemovals) { animateRemoveImpl(holder); } mPendingRemovals.clear(); // Next, move stuff if (movesPending) { final ArrayList moves = new ArrayList<>(); moves.addAll(mPendingMoves); mMovesList.add(moves); mPendingMoves.clear(); Runnable mover = new Runnable() { @Override public void run() { for (MoveInfo moveInfo : moves) { animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY); } moves.clear(); mMovesList.remove(moves); } }; if (removalsPending) { View view = moves.get(0).holder.itemView; ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); } else { mover.run(); } } // Next, change stuff, to run in parallel with move animations if (changesPending) { final ArrayList changes = new ArrayList<>(); changes.addAll(mPendingChanges); mChangesList.add(changes); mPendingChanges.clear(); Runnable changer = new Runnable() { @Override public void run() { for (ChangeInfo change : changes) { animateChangeImpl(change); } changes.clear(); mChangesList.remove(changes); } }; if (removalsPending) { ViewHolder holder = changes.get(0).oldHolder; ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); } else { changer.run(); } } // Next, add stuff if (additionsPending) { final ArrayList additions = new ArrayList<>(); additions.addAll(mPendingAdditions); mAdditionsList.add(additions); mPendingAdditions.clear(); Runnable adder = new Runnable() { @Override public void run() { for (ViewHolder holder : additions) { animateAddImpl(holder); } additions.clear(); mAdditionsList.remove(additions); } }; if (removalsPending || movesPending || changesPending) { long removeDuration = removalsPending ? getRemoveDuration() : 0; long moveDuration = movesPending ? getMoveDuration() : 0; long changeDuration = changesPending ? getChangeDuration() : 0; long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); View view = additions.get(0).itemView; ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); } else { adder.run(); } } } @Override public boolean animateRemove(final ViewHolder holder) { resetAnimation(holder); mPendingRemovals.add(holder); return true; } private void animateRemoveImpl(final ViewHolder holder) { final View view = holder.itemView; final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); mRemoveAnimations.add(holder); /** * 修改 @iwanghang */ animation.setDuration(getRemoveDuration()) //.alpha(0).setListener(new VpaListenerAdapter() { // RecyclerView原始代碼 .translationX(view.getWidth()).setListener(new VpaListenerAdapter() { // 修改後的代碼 @iwanghang @Override public void onAnimationStart(View view) { dispatchRemoveStarting(holder); } @Override public void onAnimationEnd(View view) { animation.setListener(null); //ViewCompat.setAlpha(view, 1); // RecyclerView原始代碼 ViewCompat.setTranslationX(view, 0); // 我們修改後的代碼 dispatchRemoveFinished(holder); mRemoveAnimations.remove(holder); dispatchFinishedWhenDone(); } }).start(); } @Override public boolean animateAdd(final ViewHolder holder) { resetAnimation(holder); /** * 修改 @iwanghang */ //ViewCompat.setAlpha(holder.itemView, 0); // RecyclerView原始代碼 ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getWidth()); // 修改後的代碼 @iwanghang mPendingAdditions.add(holder); return true; } void animateAddImpl(final ViewHolder holder) { final View view = holder.itemView; final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); mAddAnimations.add(holder); /** * 修改 @iwanghang */ //animation.alpha(1).setDuration(getAddDuration()). // RecyclerView原始代碼 animation.translationX(0).setDuration(getAddDuration()). // 修改後的代碼 @iwanghang setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchAddStarting(holder); } @Override public void onAnimationCancel(View view) { //ViewCompat.setAlpha(view, 1); // RecyclerView原始代碼 ViewCompat.setTranslationX(view, 0); // 修改後的代碼 @iwanghang } @Override public void onAnimationEnd(View view) { animation.setListener(null); dispatchAddFinished(holder); mAddAnimations.remove(holder); dispatchFinishedWhenDone(); } }).start(); } @Override public boolean animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { final View view = holder.itemView; fromX += ViewCompat.getTranslationX(holder.itemView); fromY += ViewCompat.getTranslationY(holder.itemView); resetAnimation(holder); int deltaX = toX - fromX; int deltaY = toY - fromY; if (deltaX == 0 && deltaY == 0) { dispatchMoveFinished(holder); return false; } if (deltaX != 0) { ViewCompat.setTranslationX(view, -deltaX); } if (deltaY != 0) { ViewCompat.setTranslationY(view, -deltaY); } mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); return true; } void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { final View view = holder.itemView; final int deltaX = toX - fromX; final int deltaY = toY - fromY; if (deltaX != 0) { ViewCompat.animate(view).translationX(0); } if (deltaY != 0) { ViewCompat.animate(view).translationY(0); } // TODO: make EndActions end listeners instead, since end actions aren't called when // vpas are canceled (and can't end them. why?) // need listener functionality in VPACompat for this. Ick. final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); /** * 修改 @iwanghang */ animation.rotationXBy(360); // X軸旋轉 @iwanghang mMoveAnimations.add(holder); animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchMoveStarting(holder); } @Override public void onAnimationCancel(View view) { if (deltaX != 0) { ViewCompat.setTranslationX(view, 0); } if (deltaY != 0) { ViewCompat.setTranslationY(view, 0); } } @Override public void onAnimationEnd(View view) { animation.setListener(null); dispatchMoveFinished(holder); mMoveAnimations.remove(holder); dispatchFinishedWhenDone(); } }).start(); } @Override public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { if (oldHolder == newHolder) { // Don't know how to run change animations when the same view holder is re-used. // run a move animation to handle position changes. return animateMove(oldHolder, fromX, fromY, toX, toY); } final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); resetAnimation(oldHolder); int deltaX = (int) (toX - fromX - prevTranslationX); int deltaY = (int) (toY - fromY - prevTranslationY); // recover prev translation state after ending animation ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); if (newHolder != null) { // carry over translation values resetAnimation(newHolder); ViewCompat.setTranslationX(newHolder.itemView, -deltaX); ViewCompat.setTranslationY(newHolder.itemView, -deltaY); /** * 修改 @iwanghang */ //ViewCompat.setAlpha(newHolder.itemView, 0); // RecyclerView原始代碼 ViewCompat.setTranslationX(newHolder.itemView, -newHolder.itemView.getWidth()); // 修改後的代碼 @iwanghang } mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); return true; } void animateChangeImpl(final ChangeInfo changeInfo) { final ViewHolder holder = changeInfo.oldHolder; final View view = holder == null ? null : holder.itemView; final ViewHolder newHolder = changeInfo.newHolder; final View newView = newHolder != null ? newHolder.itemView : null; if (view != null) { final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration( getChangeDuration()); mChangeAnimations.add(changeInfo.oldHolder); oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); /** * 修改 @iwanghang */ //oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { // RecyclerView原始代碼 oldViewAnim.translationX(view.getWidth()).setListener(new VpaListenerAdapter() { // 修改後的代碼 @iwanghang @Override public void onAnimationStart(View view) { dispatchChangeStarting(changeInfo.oldHolder, true); } @Override public void onAnimationEnd(View view) { oldViewAnim.setListener(null); ViewCompat.setAlpha(view, 1); ViewCompat.setTranslationX(view, 0); ViewCompat.setTranslationY(view, 0); dispatchChangeFinished(changeInfo.oldHolder, true); mChangeAnimations.remove(changeInfo.oldHolder); dispatchFinishedWhenDone(); } }).start(); } if (newView != null) { final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); mChangeAnimations.add(changeInfo.newHolder); newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). alpha(1).setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchChangeStarting(changeInfo.newHolder, false); } @Override public void onAnimationEnd(View view) { newViewAnimation.setListener(null); ViewCompat.setAlpha(newView, 1); ViewCompat.setTranslationX(newView, 0); ViewCompat.setTranslationY(newView, 0); dispatchChangeFinished(changeInfo.newHolder, false); mChangeAnimations.remove(changeInfo.newHolder); dispatchFinishedWhenDone(); } }).start(); } } private void endChangeAnimation(List infoList, ViewHolder item) { for (int i = infoList.size() - 1; i >= 0; i--) { ChangeInfo changeInfo = infoList.get(i); if (endChangeAnimationIfNecessary(changeInfo, item)) { if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { infoList.remove(changeInfo); } } } } private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { if (changeInfo.oldHolder != null) { endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); } if (changeInfo.newHolder != null) { endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); } } private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) { boolean oldItem = false; if (changeInfo.newHolder == item) { changeInfo.newHolder = null; } else if (changeInfo.oldHolder == item) { changeInfo.oldHolder = null; oldItem = true; } else { return false; } ViewCompat.setAlpha(item.itemView, 1); ViewCompat.setTranslationX(item.itemView, 0); ViewCompat.setTranslationY(item.itemView, 0); dispatchChangeFinished(item, oldItem); return true; } @Override public void endAnimation(ViewHolder item) { final View view = item.itemView; // this will trigger end callback which should set properties to their target values. ViewCompat.animate(view).cancel(); // TODO if some other animations are chained to end, how do we cancel them as well? for (int i = mPendingMoves.size() - 1; i >= 0; i--) { MoveInfo moveInfo = mPendingMoves.get(i); if (moveInfo.holder == item) { ViewCompat.setTranslationY(view, 0); ViewCompat.setTranslationX(view, 0); dispatchMoveFinished(item); mPendingMoves.remove(i); } } endChangeAnimation(mPendingChanges, item); if (mPendingRemovals.remove(item)) { ViewCompat.setAlpha(view, 1); dispatchRemoveFinished(item); } if (mPendingAdditions.remove(item)) { ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); } for (int i = mChangesList.size() - 1; i >= 0; i--) { ArrayList changes = mChangesList.get(i); endChangeAnimation(changes, item); if (changes.isEmpty()) { mChangesList.remove(i); } } for (int i = mMovesList.size() - 1; i >= 0; i--) { ArrayList moves = mMovesList.get(i); for (int j = moves.size() - 1; j >= 0; j--) { MoveInfo moveInfo = moves.get(j); if (moveInfo.holder == item) { ViewCompat.setTranslationY(view, 0); ViewCompat.setTranslationX(view, 0); dispatchMoveFinished(item); moves.remove(j); if (moves.isEmpty()) { mMovesList.remove(i); } break; } } } for (int i = mAdditionsList.size() - 1; i >= 0; i--) { ArrayList additions = mAdditionsList.get(i); if (additions.remove(item)) { ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); if (additions.isEmpty()) { mAdditionsList.remove(i); } } } // animations should be ended by the cancel above. //noinspection PointlessBooleanExpression,ConstantConditions if (mRemoveAnimations.remove(item) && DEBUG) { throw new IllegalStateException("after animation is cancelled, item should not be in " + "mRemoveAnimations list"); } //noinspection PointlessBooleanExpression,ConstantConditions if (mAddAnimations.remove(item) && DEBUG) { throw new IllegalStateException("after animation is cancelled, item should not be in " + "mAddAnimations list"); } //noinspection PointlessBooleanExpression,ConstantConditions if (mChangeAnimations.remove(item) && DEBUG) { throw new IllegalStateException("after animation is cancelled, item should not be in " + "mChangeAnimations list"); } //noinspection PointlessBooleanExpression,ConstantConditions if (mMoveAnimations.remove(item) && DEBUG) { throw new IllegalStateException("after animation is cancelled, item should not be in " + "mMoveAnimations list"); } dispatchFinishedWhenDone(); } private void resetAnimation(ViewHolder holder) { AnimatorCompatHelper.clearInterpolator(holder.itemView); endAnimation(holder); } @Override public boolean isRunning() { return (!mPendingAdditions.isEmpty() || !mPendingChanges.isEmpty() || !mPendingMoves.isEmpty() || !mPendingRemovals.isEmpty() || !mMoveAnimations.isEmpty() || !mRemoveAnimations.isEmpty() || !mAddAnimations.isEmpty() || !mChangeAnimations.isEmpty() || !mMovesList.isEmpty() || !mAdditionsList.isEmpty() || !mChangesList.isEmpty()); } /** * Check the state of currently pending and running animations. If there are none * pending/running, call {@link #dispatchAnimationsFinished()} to notify any * listeners. */ void dispatchFinishedWhenDone() { if (!isRunning()) { dispatchAnimationsFinished(); } } @Override public void endAnimations() { int count = mPendingMoves.size(); for (int i = count - 1; i >= 0; i--) { MoveInfo item = mPendingMoves.get(i); View view = item.holder.itemView; ViewCompat.setTranslationY(view, 0); ViewCompat.setTranslationX(view, 0); dispatchMoveFinished(item.holder); mPendingMoves.remove(i); } count = mPendingRemovals.size(); for (int i = count - 1; i >= 0; i--) { ViewHolder item = mPendingRemovals.get(i); dispatchRemoveFinished(item); mPendingRemovals.remove(i); } count = mPendingAdditions.size(); for (int i = count - 1; i >= 0; i--) { ViewHolder item = mPendingAdditions.get(i); View view = item.itemView; ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); mPendingAdditions.remove(i); } count = mPendingChanges.size(); for (int i = count - 1; i >= 0; i--) { endChangeAnimationIfNecessary(mPendingChanges.get(i)); } mPendingChanges.clear(); if (!isRunning()) { return; } int listCount = mMovesList.size(); for (int i = listCount - 1; i >= 0; i--) { ArrayList moves = mMovesList.get(i); count = moves.size(); for (int j = count - 1; j >= 0; j--) { MoveInfo moveInfo = moves.get(j); ViewHolder item = moveInfo.holder; View view = item.itemView; ViewCompat.setTranslationY(view, 0); ViewCompat.setTranslationX(view, 0); dispatchMoveFinished(moveInfo.holder); moves.remove(j); if (moves.isEmpty()) { mMovesList.remove(moves); } } } listCount = mAdditionsList.size(); for (int i = listCount - 1; i >= 0; i--) { ArrayList additions = mAdditionsList.get(i); count = additions.size(); for (int j = count - 1; j >= 0; j--) { ViewHolder item = additions.get(j); View view = item.itemView; ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); additions.remove(j); if (additions.isEmpty()) { mAdditionsList.remove(additions); } } } listCount = mChangesList.size(); for (int i = listCount - 1; i >= 0; i--) { ArrayList changes = mChangesList.get(i); count = changes.size(); for (int j = count - 1; j >= 0; j--) { endChangeAnimationIfNecessary(changes.get(j)); if (changes.isEmpty()) { mChangesList.remove(changes); } } } cancelAll(mRemoveAnimations); cancelAll(mMoveAnimations); cancelAll(mAddAnimations); cancelAll(mChangeAnimations); dispatchAnimationsFinished(); } void cancelAll(List viewHolders) { for (int i = viewHolders.size() - 1; i >= 0; i--) { ViewCompat.animate(viewHolders.get(i).itemView).cancel(); } } /** * {@inheritDoc} * * If the payload list is not empty, DefaultItemAnimator returns
true. * When this is the case: *
*
If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both * ViewHolder arguments will be the same instance. *
*
* If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and * run a move animation instead. *
*
*/ @Override public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder, @NonNull List
MainActivity.java:
package com.iwanghang.recyclerviewdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* RecyclerView 可以簡單的理解為ListView
*/
public class MainActivity extends AppCompatActivity implements MyAdapter.OnMyItemClickListener {
RecyclerView recycler;
MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recycler = (RecyclerView) findViewById(R.id.recycler);
List list = new ArrayList<>();
for (int i = 0; i <100 ; i++) {
list.add(String.format(Locale.CHINA,"第%03d條數據",i));
// list.add(String.format(Locale.CHINA,"第%03d條數據%s", i, i % 2 == 0 ? "" : "" +
// "據據據據據據據據據據據據據據據據據據據據據據據據據據據據據"));
}
adapter = new MyAdapter(this,list);
//
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
// 瀑布流(不規則的網格布局)
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL);
// 動畫效果
//DefaultItemAnimator animator = new DefaultItemAnimator(); // RecyclerView默認的屬性動畫
MyItemAnimator animator = new MyItemAnimator(); // 我們自己的屬性動畫
animator.setRemoveDuration(2000); // 刪除動畫的延遲時間
animator.setMoveDuration(2000); // 移動動畫的延遲時間
animator.setAddDuration(2000); // 增加動畫的延遲時間
animator.setSupportsChangeAnimations(true); // 還要改變動畫需要設置支持
animator.setChangeDuration(2000); // 改變動畫的延遲時間
recycler.setLayoutManager(linearLayoutManager);
recycler.setItemAnimator(animator);
recycler.setAdapter(adapter);
adapter.setOnMyItemClickListener(this);
}
@Override
public void onMyItemClick(RecyclerView parent, View view, int position, String data) {
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
//adapter.remove(position); // 刪除數據
//adapter.add(position,"New"); // 添加數據
adapter.change(position,"Change"); // 改變數據
}
}
這是在網上找的,不過忘了在哪裡找的,經過很多比較測試,發現這個方法不會 oom,目前來看 我一直沒有遇過,今天才找到這個以前建立的工程,記錄下來:先給大家展示下效果圖:p
進入開發者模式後就可以導入接口信息,這樣在服務上增加的功能就能生效;如果你不想太折騰直接使用現成的微信公眾賬號功能可以使用楚盟提供的第三方微信公眾平台;免費
下面先來一張效果圖 根據圖片分析,要實現的有側邊欄DrawerLayout,ActionBar的顏色和菜單以及ActionBarDrawerTogg
一、簡介 地圖控件自v2.3.5版本起,支持多實例,即開發者可以在一個頁面中建立多個地圖對象,並且針對這些對象分別操作且不會產生相互干擾。 文件名:D