Есть список на основе ListView и SimpleCursorAdapter и SQLite.
Пишу Swipe строки списка с помощью анимации. В ACTION_MOVE строка списка должна двигаться влево за пальцем и при достижении определенного значения по оси X менять цвет и ставать доступной для удаления. В этой зоне при ACTION_UP строка должна удалиться с БД по найденому ID. Соответствующе в перерисованом ListView строка с удаляемой позицией исчезает из списка на экране. Все это работает, но возникает следующая проблемма:
При добавлении в БД новой строки она появляется в списке на экране в том состоянии и в том положении по оси X которое было у ранее удаленной строки.
Предполагаю что, скорее всего, где-то ListView держит ранее использованные вьюхи с теми характеристиками с которыми они были ранее удалены и заливает туда новые строки с БД.
Пробовал применять после удаления: notifyDataSetChanged(), завершение анимации - эффекта нет.
public class MainActivity extends AppCompatActivity implements View.OnClickListener,
View.OnTouchListener, LoaderManager.LoaderCallbacks
DB db;
DBHelper dbHelper;
SimpleCursorAdapter scAdapter;
Context context;
String name;
String kind;
private View onTouchedItemView;
ListView lv_list;
Button btnEmpty, btnAdd, btnRead, btnClear;
TextView tvNameId, tvNameName, tvNameKind, tvNameCost;
EditText tvName, tvKind;
private int pointDownX;
private int pointDownY;
private long touchedItemID;
private int targetPoint;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DB(this);
db.open();
String[] from = new String[]{DB.KEY_ID, DB.KEY_NAME, DB.KEY_KIND, DB.KEY_COST};
int[] to = new int[]{R.id.tvListId, R.id.tvListName, R.id.tvListKind, R.id.tvListCost};
scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
lv_list = (ListView) findViewById(R.id.lv_list);
lv_list.setAdapter(scAdapter);
lv_list.setOnTouchListener(this);
getSupportLoaderManager().initLoader(0, null, this);
tvNameId = (TextView) findViewById(R.id.tvNameId);
tvNameName = (TextView) findViewById(R.id.tvNameName);
tvNameKind = (TextView) findViewById(R.id.tvNameKind);
tvNameCost = (TextView) findViewById(R.id.tvNameCost);
tvName = (EditText) findViewById(R.id.tvName);
tvName.setOnClickListener(this);
tvKind = (EditText) findViewById(R.id.tvKind);
tvKind.setOnClickListener(this);
btnAdd = (Button) findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(this);
btnEmpty = (Button) findViewById(R.id.btnEmpty);
btnEmpty.setOnClickListener(this);
btnRead = (Button) findViewById(R.id.btnRead);
btnRead.setOnClickListener(this);
btnClear = (Button) findViewById(R.id.btnClear);
btnClear.setOnClickListener(this);
}
@Override
public void onClick(View view) {
name = tvName.getText().toString();
kind = tvKind.getText().toString();
switch (view.getId()) {
case R.id.btnAdd:
if (kind.isEmpty()) {
kind = "1";
}
if (name.isEmpty()) {
Toast.makeText(getApplicationContext(),
"Fill all fields", Toast.LENGTH_SHORT).show();
} else {
db.addRec(name, kind);
getSupportLoaderManager().getLoader(0).forceLoad();
tvName.setText("");
tvKind.setText("");
}
break;
case R.id.btnEmpty:
tvName.setText("");
tvKind.setText("");
break;
case R.id.btnRead:
getSupportLoaderManager().getLoader(0).forceLoad();
break;
case R.id.btnClear:
db.delAllRec();
getSupportLoaderManager().getLoader(0).forceLoad();
break;
}
}
@Override
public Loader
@Override
public void onLoadFinished(Loader
@Override
public void onLoaderReset(Loader
@Override
public boolean onTouch(View v, MotionEvent event) {
int dispWidth = v.getWidth();
int horizontalMinDistance = dispWidth / 4;
int distFromRightBorder = dispWidth - pointDownX;
int distToMeet = pointDownX / 10;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
pointDownX = (int) event.getX();
pointDownY = (int) event.getY();
onTouchedItemView = lv_list.getChildAt(lv_list.pointToPosition(pointDownX, pointDownY));
touchedItemID = lv_list.pointToRowId(pointDownX, pointDownY);
return true;
case MotionEvent.ACTION_MOVE:
int pointMovingX = (int) event.getX();
int deltaX = pointDownX - pointMovingX;
int distGone = distFromRightBorder / distToMeet * Math.abs(deltaX);
if (deltaX < 0) {
if (Math.abs(deltaX) < distToMeet) {
targetPoint = dispWidth - pointMovingX + pointDownX - distGone;
} else {
targetPoint = pointMovingX;
}
anim();
} else {
if (Math.abs(deltaX) < distToMeet) {
targetPoint = pointMovingX - dispWidth + distFromRightBorder - distGone;
} else {
targetPoint = pointMovingX - dispWidth;
if (Math.abs(deltaX) > horizontalMinDistance && pointMovingX < dispWidth / 8) {
onTouchedItemView.setBackgroundResource(R.color.deletemarker);
} else {
onTouchedItemView.setBackgroundResource(R.color.backgroundmain);
}
}
anim();
}
return true;
case MotionEvent.ACTION_UP:
float upX = (int) event.getRawX();
if (upX < dispWidth / 8) {
db.delRec(touchedItemID);
getSupportLoaderManager().getLoader(0).forceLoad();
} else {
targetPoint = 0;
anim();
}
return true;
}
return true;
}
public void anim() {
onTouchedItemView.animate()
.x(targetPoint)
.setDuration(0)
.start();
}
private static class MyCursorLoader extends CursorLoader {
DB db;
public MyCursorLoader(Context context, DB db) {
super(context);
this.db = db;
}
@Override
public Cursor loadInBackground() {
Cursor cursor = db.getAllData();
return cursor;
}
}
protected void onDestroy() {
super.onDestroy();
db.close();
}
}
Ответ
Нашел решение.
Применил обратную анимацию перед обновлением списка.
onTouchedItemView.setBackgroundResource(R.color.backgroundmain);
targetPoint = 0;
anim();
И метод:
clearDisappearingChildren();
Он удаляет анимацию на удаленном элементе списка.
В коде выглядит так:
case MotionEvent.ACTION_UP:
float upX = (int) event.getRawX();
if (upX < dispWidth / 8) {
db.delRec(touchedItemID);
lv_list.clearDisappearingChildren();
getSupportLoaderManager().getLoader(0).forceLoad();
onTouchedItemView.setBackgroundResource(R.color.backgroundmain);
targetPoint = 0;
anim();
} else {
targetPoint = 0;
anim();
}
return true;
Комментариев нет:
Отправить комментарий