我正在尝试使用拖放重新排列视图(特别是卡片)。
我对简单实现的初步想法是通过从父项中删除它然后将其添加到左侧或右侧的位置来重新定位视图。
这似乎在没有动画的情况下工作正常,但是一旦我开始使用动画,有时卡会卡住。我收到错误:
java.lang.NullPointerException:尝试从字段读取 'android.view.IWindowSession android.view.View $ AttachInfo.mSession'on 一个空对象引用 android.view.View.startDrag(View.java:18353)at cz.cvut.mazelmir.cards.Cards $ $ AFragment 2.onTouch(Anagram.java:158)
我不太清楚要做什么,因为传递给onTouch
的内容是被触摸的视图(不应该为null)和新创建的参数。
有关为何发生这种情况的任何线索以及我可以采取哪些措施来解决这个问题? 或者至少有一些关于如何最好地实现这种拖放功能的提示? (也许是一个简单的框架视图,我只是为卡片设置动画?)
以下是包含卡片段的代码:(片段布局只是一个线性布局,卡片布局包含一个文本视图。)
public static class AFragment extends Fragment {
String s = "string";
ViewGroup emptyContainer;
View[] cards;
float[] cardLoc;
public AFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
LinearLayout linearLayout = (LinearLayout) inflater.inflate(R.layout.fragment_anagram, container, false);
emptyContainer = null;
cards = null;
cardLoc = null;
createCards(inflater, linearLayout, s);
linearLayout.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View view, DragEvent event) {
View draggedItem = (View) event.getLocalState();
ViewGroup viewGroup = (ViewGroup) view;
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
if (cardLoc == null)
createPositions();
emptyContainer = viewGroup;
draggedItem.setVisibility(View.INVISIBLE);
break;
case DragEvent.ACTION_DRAG_LOCATION:
int emptyPos = (int)draggedItem.getTag(R.id.position_tag);
float currentX = event.getX();
// To the right?
if (emptyPos < cardLoc.length - 1 && currentX > cardLoc[emptyPos + 1]) {
viewGroup.removeView(cards[emptyPos + 1]);
viewGroup.addView(cards[emptyPos + 1], emptyPos);
TranslateAnimation translateAnimation = new TranslateAnimation(cardLoc[emptyPos + 1] - cardLoc[emptyPos], 0, 0, 0);
translateAnimation.setDuration(200);
cards[emptyPos + 1].startAnimation(translateAnimation);
View tempView = cards[emptyPos + 1];
cards[emptyPos + 1] = cards[emptyPos];
cards[emptyPos] = tempView;
draggedItem.setTag(R.id.position_tag, emptyPos + 1);
tempView.setTag(R.id.position_tag, emptyPos);
}
// To the left?
else if (emptyPos > 0 && currentX < cardLoc[emptyPos]) {
viewGroup.removeView(cards[emptyPos - 1]);
viewGroup.addView(cards[emptyPos - 1], emptyPos);
TranslateAnimation translateAnimation = new TranslateAnimation(cardLoc[emptyPos - 1] - cardLoc[emptyPos], 0, 0, 0);
translateAnimation.setDuration(200);
cards[emptyPos - 1].startAnimation(translateAnimation);
View tempView = cards[emptyPos - 1];
cards[emptyPos - 1] = cards[emptyPos];
cards[emptyPos] = tempView;
draggedItem.setTag(R.id.position_tag, emptyPos - 1);
tempView.setTag(R.id.position_tag, emptyPos);
}
break;
case DragEvent.ACTION_DRAG_ENDED:
draggedItem.setVisibility(View.VISIBLE);
break;
default:
break;
}
return true;
}
});
return linearLayout;
}
private void createCards(LayoutInflater inflater, LinearLayout container, String s) {
cards = new View[s.length()];
int j = 0;
for (char c : s.toCharArray()) {
String letter = String.valueOf(c);
View letterCard = inflater.inflate(R.layout.letter_container, container, false);
TextView letterTextView = (TextView) letterCard.findViewById(R.id.letter_text);
letterTextView.setText(letter);
letterCard.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
return true;
}
return false;
}
});
cards[j] = letterCard;
container.addView(letterCard);
letterCard.setTag(R.id.position_tag, j);
letterCard.setTag(R.id.letter_tag, letter);
j++;
}
}
public void createPositions() {
cardLoc = new float[cards.length];
for (int i = 0; i < cards.length; i++) {
cardLoc[i] = cards[i].getX();
}
}
}
}