首先先说思路
1创建MyListView类 extends ListView 重写三个构造方法,
2在xml里面引用<com.example.yangai00.yy_shuxingdonghua.MyListView 然后在MainActivity里面初始化控件
3获取数据,调用适配器(我用的是系统默认的)适配数据 重写getView()方法(适配器里面细节。。。。。略)
4引入顶部试图,调用addHeaderView(”添加引入的布局的View“),初始化控件
5在MyListView里面自定义方法getImgView(要引入的顶部试图控件);
6在MainActivity里面调用getImgView(传入第4步引入顶部试图的初始化控件ID)
7在getImgView()里面通过传入的参数给全局变量赋值(this.IV = v),然后IV.调用
getViewTreeObserver().addOnGlobalLayoutListener()方法,重写onGlobalLayout()方法,在onGlobalLayout()方法里面获取控件的高度(IV.getHeight()),防止此方法可能会多次调用,定义boolean类型变量为true,if判断之后重新给boolean变量重新赋值为false
8在通过调用getDrawable().getIntrinsicHeight()方法来获取图片的高度;
9比较控件的高度和图片的高度,最后把大的值,赋值给新的int 类型的max变量
10重写overScrollBy();参数.deltaX 是x轴向上滑动的距离,参数.deltaY是Y轴向上滑动的距离,参数:maxOverScrollX 是X轴滑动的最大距离 maxOverScrollY 是Y轴滑动的最大距离,参数:isTouchEvent 为true代表滑动 为false代表惯性滑动,在overScrollBy()方法里面首先ImageView判空 接着在判断是否是向下滑动和isTouchEvent是为true,如果条件成立,证明是在向下滑动,我们要获取当前滑动的高度,在判断如果当前的高度大于第9步中的max(最大高度)就把max最大的高度赋值给当前的高度,在把当前获得的新的高度赋值给图片的高度,然后调用requestLayout()方法刷新
11 重写onTouchEvent手势监听方法,在手势抬起的时候添加属性动画,通过属性动画让图片回弹 ,首先导入implementation files('libs/nineoldandroids-2.2.0.jar')依赖,通过ObjectAnimator.ofInt(参数:当前的高度,原始的高度)方法创建动画,获取动画的监听器,在监听器里面通过valueAnimator.getAnimatedValue()方法来获取动画的已个过度值(0.....1),通过setIntValues()来设置过度值,接着设置动画的时间,开启动画。
这只是已个简单的自定义listView顶部图片下拉放大和回弹效果,写了这么多,只是为了大家好更好的理解。
思路说完了下面是代码展示:
自定义ListView类:
public class MyListView extends ListView {
//顶部图片
private ImageView IV;
//当前的高度
private int div;
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//控件的高
private int kong_height;
//图片的高
private int tu_height;
//最大高度
private int mMaxheight;
private Boolean feng = true;
//自定义方法用于传ImageView
public void getImgView(ImageView v) {
this.IV = v;
IV.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//在此处获取控件的高度,为了只获取一次,加个Boolean判断
if (feng) {
kong_height = IV.getHeight();
feng = false;
}
}
});
//获取图片的高度
tu_height = IV.getDrawable().getIntrinsicHeight();
//把大的值赋值给最大高度
mMaxheight = kong_height > tu_height ? kong_height + 200 : tu_height;
}
//用于记录滑动的时候的x和y轴坐标
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
if (IV != null) {
//判断是否向下和滑动
if (deltaY < 0 && isTouchEvent) {
//获取当前高度
div = IV.getHeight() - deltaY;
//当前高度大于最大高度把最大高度赋值给当前高度
if (div > mMaxheight) {
div = mMaxheight;
}
//把获取到 的新高度赋值给params.height进行拉伸
ViewGroup.LayoutParams params = IV.getLayoutParams();
params.height = div;
//刷新
requestLayout();
}
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
//手势监听
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
//手指抬起
case MotionEvent.ACTION_UP:
//添加属性动画进行回弹IV.getHeight为下拉后当前高度,kong_height为原始状态
ValueAnimator valueAnimator = com.nineoldandroids.animation.ObjectAnimator.ofInt(IV.getHeight(), kong_height);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animatedValue = (int) valueAnimator.getAnimatedValue();
IV.getLayoutParams().height = animatedValue;
requestLayout();
}
});
//动画时间
valueAnimator.setDuration(100);
//开始
valueAnimator.start();
break;
}
return super.onTouchEvent(ev);
}
}
xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.yangai00.yy_shuxingdonghua.MyListView
android:id="@+id/mLV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#000"
android:dividerHeight="1dp">
</com.example.yangai00.yy_shuxingdonghua.MyListView>
</LinearLayout>
主页面:
public class MainActivity extends AppCompatActivity {
//初始化控件
private MyListView mLV;
//linstView数据
private String[] yun = {"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "I", "O", "P", "U", "Y", "T", "R", "W", "Q", "S", "L", "Z", "X", "V", "N", "M"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
//创建适配器
ArrayAdapter<String> MyAdaptes = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, yun) {
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.my_listview, null);
TextView mTV = convertView.findViewById(R.id.mText);
mTV.setText(yun[position]);
}
return convertView;
}
};
mLV.setAdapter(MyAdaptes);
//添加listView顶部View试图
View v = View.inflate(MainActivity.this, R.layout.my_img, null);
mLV.addHeaderView(v);
ImageView viewById = v.findViewById(R.id.mImg);
//将ImageView的ID传到适配器
mLV.getImgView(viewById);
}
private void initView() {
//初始化
mLV = (MyListView) findViewById(R.id.mLV);
}
}
其他的两个xml布局就不展示了 ,到此整个代码结束。