```java
package com.example.shiyan31;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.example.shiyan31.R;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private String a;//全局变量,记录点击哪一项
private ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.MyListView);
List<String>list=new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("狗子");
list.add("小王");
list.add("小红");
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String mag =adapter.getItem(position);
a = mag;
final Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("name", mag.toString());
startActivityForResult(intent, 1);
}
});}
protected void onActivityResult(int requestCode,int resultCode, Intent data) {//requestCode 为父界面的编号
//resultCode 为子界面的返回编号
//data可以使传递的值
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == 2) {
adapter.remove(a);
}
}
}
SecondActivity.java
```java
package com.example.shiyan31;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.shiyan31.R;
public class SecondActivity extends AppCompatActivity {
private int index;
private String name=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
final Intent intent1;
intent1=getIntent();
name=intent1.getStringExtra("name");
AlertDialog dialog=new AlertDialog.Builder(SecondActivity.this.getApplicationContext())
.setMessage("删除"+name+"的记录吗?")
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
Intent intent=new Intent();
public void onClick(DialogInterface dialog, int which) {
setResult(2,intent);//设置子界面的编号并返回
finish();
}
})
.create();
dialog.show();
}
}
activity_main.xml
```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ListView
android:id="@+id/MyListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbarSize="30sp"
android:dividerHeight="5dp"
android:headerDividersEnabled="true"/>
</LinearLayout>
activity_second.xml
```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
</LinearLayout>
工程
build.gradle版本
这一页代码都贴上来吧
下面是针对我的问题,一个个解决。
一般我们在做dialog的时候,最常用的是设置dialog的进入和出去的动画,这个一般在onCreateDialog的时候,通过window去设置。就是下面的代码。
Window window = dialog.getWindow(); if (window != null) { window.setWindowAnimations(R.style.dialog_animation); } 这里顺便带一句,如果要设置或者取消外部点击消失,用这个方法dialog.setCanceledOnTouchOutside(true);这个方法一般也是在onCreateDialog的时候设置就可以了。 但是,通过设置style我们无法很精确的移动到我们需要的坐标位置,而且移动位置如果有一点变化,可能需要重新计算等问题。 所以,我们需要在代码中,通过计算使动画移动的位置更准确。这个时候就需要思考怎么给整个dialog设置动画了。 一开始我一直在考虑怎么给整个dialog设置动画,然后通过getdialog获取到dialog的对象以后,无法把animator设置给dialog,提示我说动画只能针对view设置。后来突然发现,思路进入牛角尖了,dialog的view不就是view嘛,然后我就直接通过getview或者可以通过获取dialog的最外层布局即可获取到需要设置动画的对象。到这里,我们的动画就有了思路。
动画的选择方面,我这边使用的是属性动画ObjectAnimator。属性动画会直接改变控件的属性,即在动画完成以后,实际位置/大 小/透明度都发生了改变的,常用的属性动画有缩放/平移/渐变度的改变。这边稍微说明一下,详细可以百度属性动画自行了解。我们这次的需求只需要使用一个缩放 + 平移即可。
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(getView(), "scaleX",1, 0.1f); 说明一下这里的参数,第一个是需要做动画的view,第二个scaleX是针对x轴进行缩放,后面的参数是变化的值,如我这里,从原大小变成0.1倍的大小,当然你也可以从0 -> 1.0f 。你也可以设置(0.1f, 1.0f, 0.5f, 2.0f)这里可以传多个值。同理可以设置scaleY。针对Y进行变换。缩放动画就这几个。 ObjectAnimator transXAnim = ObjectAnimator.ofFloat(getView(), "translationX",0, tranX); 这个是平移动画,前2个参数相同。后面的参数说明一下,我使用的时候,也是很久没用了,最开始以为是从0的位置移动到tranX这个坐标,后来发现是向x轴移动tranX位置。所以我们需要计算,动画需要在x上移动的距离。 int tranX = tranToX - tranStartX; (移动距离 = 目标位置x点坐标 - 当前位置x点坐标) 。然后把这个移动距离设置到动画数值那里即可,类似旋转的。当然也可以设置多个值,比如先右X移动100个距离,然后再向左移动200个位置,然后再向右移动50个位置。(getView(), "translationX",100, -200,50);(X移动时正为向右,负数为向左移动。同理Y轴移动的时候,正为向下,负数向上移动)其余就不过多介绍属性动画了,设置一个动画持续时间,设置一个动画循环的次数,通过.playTogether(动画A, 动画B); start()动画即可。 突然想起来了,这里目标位置的坐标获取说明一下:目标位置一般都是移动到某个view上。我这边是通过下面这个方法 int[] location = new int[2]; mTargerView.getLocationInWindow(location); 通过获取目标位置在屏幕中的位置,这样会比较准备。当然具体做动画的时候要根据移动的位置计算一下view的宽高。
动画执行的时候碰到或者有跳动,或者有消失等等问题。对了,这里需要说一下,要把原来的dialog移除的时候的动画移除了,不然dialog在移除的时候还有一个动画,即最开始说的常用dialog进入和退出时的动画。最开始猜想可能是位置计算有错,我一开始是毛估估的计算了动画移动的位置,没有按照上面说的精确计算,这样可以解决动画跳动的问题。然后就是动画走到快要结束的地方有一个消失的情况,一开始也去考虑是不是位置算错了。后来多次验证发现和距离应该没关系,动画的移动距离没问题。我在没有调用dialog的dismiss方法时,动画执行到最后ui也消失了,后来突然想到,会不会和dialog的整体宽高有关。然后就修改了整个dialog为matchparent,再设置了一个透明的背景。重新执行动画,问题解决。那我这里就猜想,动画执行时,只能在view所绘制的区域内,超出了以后就会消失。
最后把我们上面写的消失的动画设置到dialog的关闭按钮响应上即可。其余的就剩一些优化了,比如dialog销毁的时候动画的回收,dialog多次调用覆盖等问题。然后就是用户不去点击我们设置的关闭按钮,直接通过手机的返回按钮来关闭dialog,由于我们不是在dialog的dismiss()方法里面设置的动画,这就需要我们去设置dialog在点击返回按钮的回掉了。一开始我是对整个Activity的back事件进行判断,后来发现dialog自己有一个setOnKeyListener()的方法,通过重写里面的onKey方法,这样可以在dialog显示的时候监听到用户点击返回键。
getDialog().setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { Log.e("xnm", "KEYCODE_BACK"); showDismissScaleAnim(); return true; } return false; } }); 一开始是没有增加(event.getAction() == KeyEvent.ACTION_UP)判断,然后在看日志的时候发现日志打印了两遍,后来突然想到了,可能是按下和抬起的事件都监听到了,然后增加了一个判断,解决两次回调的问题。
好了,本期的分享到这里就结束了,谢谢大家,有问题请指正。