效果如上,首先是上面的安全信息部分DetailSafeHolder
public class DetailSafeHolder extends BaseHolder<DetailBean> {
@Bind(R.id.app_detail_safe_iv_arrow)
ImageView mAppDetailSafeIvArrow;
@Bind(R.id.app_detail_safe_pic_container)
LinearLayout mAppDetailSafePicContainer;
@Bind(R.id.app_detail_safe_des_container)
LinearLayout mAppDetailSafeDesContainer;
private View mSafeView;
private boolean isOpen = false;
private int mStart;
private int mEnd;
@Override
public void setContent(DetailBean detailBean) {
//添加几个绿色安全图片
addPicView(detailBean);
//添加安全描述信息
addSafeDes(detailBean);
}
@Override
public View getViewInflate() {
mSafeView = View.inflate(UiUtil.getContext(), R.layout.item_app_detail_safe, null);
ButterKnife.bind(this, mSafeView);
//设置箭头的点击监听事件
//初始不需要执行伸缩动画
toggle(false);
mAppDetailSafeIvArrow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggle(true);
}
});
return mSafeView;
}
private void toggle(boolean isAnimator) {
//首先需要测量安全信息的宽高
mAppDetailSafeDesContainer.measure(View.MeasureSpec.makeMeasureSpec(
mAppDetailSafePicContainer.getMeasuredWidth(),
View.MeasureSpec.EXACTLY), 0);
//动态定义高度
int height = mAppDetailSafeDesContainer.getMeasuredHeight();
if (isAnimator) {
//需要执行伸缩动画
if (isOpen) {
//收缩
mStart = height;
mEnd = 0;
//箭头向下动画
ObjectAnimator animator = ObjectAnimator.ofFloat(mAppDetailSafeIvArrow,"rotation",-180,0);
animator.setDuration(500);
animator.start();
} else {
//伸展
mStart = 0;
mEnd = height;
//箭头向上动画
ObjectAnimator animator = ObjectAnimator.ofFloat(mAppDetailSafeIvArrow,"rotation",0,180);
animator.setDuration(500);
animator.start();
}
//开始动画
startAnimation(mStart,mEnd);
isOpen = !isOpen;
} else {
//无需伸缩动画
ViewGroup.LayoutParams params = mAppDetailSafeDesContainer.getLayoutParams();
if (isOpen) {
//收缩
params.height = 0;
} else {
//伸展
params.height = height;
}
mAppDetailSafeDesContainer.setLayoutParams(params);
}
}
private void startAnimation(int start,int end) {
ValueAnimator animator = ValueAnimator.ofObject(new FloatEvaluator(),start,end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
ViewGroup.LayoutParams params = mAppDetailSafeDesContainer.getLayoutParams();
params.height = (int) animatedValue;
mAppDetailSafeDesContainer.setLayoutParams(params);
mAppDetailSafeDesContainer.invalidate();
}
});
animator.setDuration(500);
animator.start();
}
private void addSafeDes(DetailBean detailBean) {
for (DetailBean.SafeBean safeBean : detailBean.safe) {
LinearLayout desLayout = new LinearLayout(UiUtil.getContext());
desLayout.setGravity(Gravity.CENTER);
//添加安全描述信息里的图片部分
ImageView iv = new ImageView(UiUtil.getContext());
String url = Constant.SERVER_IMAGEURL + safeBean.safeDesUrl;
Picasso.with(UiUtil.getContext()).load(url).into(iv);
desLayout.addView(iv);
//添加文字描述信息部分
TextView tv = new TextView(UiUtil.getContext());
tv.setText(safeBean.safeDes);
desLayout.addView(tv);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
param.leftMargin = 4;
//添加到安全信息容器里
mAppDetailSafeDesContainer.addView(desLayout,param);
}
}
private void addPicView(DetailBean detailBean) {
for (DetailBean.SafeBean safeBean : detailBean.safe) {
LinearLayout picLayout = new LinearLayout(UiUtil.getContext());
picLayout.setGravity(Gravity.CENTER);
ImageView picView = new ImageView(UiUtil.getContext());
String url = Constant.SERVER_IMAGEURL + safeBean.safeUrl;
Picasso.with(UiUtil.getContext()).load(url).into(picView);
picLayout.addView(picView);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
param.leftMargin = 4;
mAppDetailSafePicContainer.addView(picLayout, param);
}
}
}
DetailSafeHolder需要填充的布局文件 item_app_detail_safe.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">
<!-- 上面部分 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/app_detail_safe_iv_arrow"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:src="@drawable/arrow_down"/>
<!-- 图片容器 -->
<LinearLayout
android:id="@+id/app_detail_safe_pic_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/app_detail_des_iv_arrow"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingTop="5dp">
</LinearLayout>
</RelativeLayout>
<!-- 下面部分 -->
<LinearLayout
android:id="@+id/app_detail_safe_des_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
下面的描述部分DetailDesHolder部分
public class DetailDesHolder extends BaseHolder<DetailBean> {
@Bind(R.id.app_detail_des_tv_des)
TextView mAppDetailDesTvDes;
@Bind(R.id.app_detail_des_tv_author)
TextView mAppDetailDesTvAuthor;
@Bind(R.id.app_detail_des_iv_arrow)
ImageView mAppDetailDesIvArrow;
private View mDesView;
private int mWidth;
private boolean isOpen = false;
private int mStart;
private int mEnd;
@Override
public void setContent(DetailBean detailBean) {
System.out.println("des==" + detailBean.des);
mAppDetailDesTvDes.setText(detailBean.des);
mAppDetailDesTvAuthor.setText("作者:" + detailBean.author);
System.out.println("author==" + detailBean.author);
}
@Override
public View getViewInflate() {
mDesView = View.inflate(UiUtil.getContext(), R.layout.item_app_detail_des, null);
ButterKnife.bind(this, mDesView);
toggle(false);
mAppDetailDesTvDes.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mWidth = mAppDetailDesTvDes.getMeasuredWidth();
mAppDetailDesTvDes.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
});
mAppDetailDesIvArrow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggle(true);
}
});
return mDesView;
}
private void toggle(boolean isAnimator) {
//首先需要测量描述信息的宽高
mAppDetailDesTvDes.measure(View.MeasureSpec.makeMeasureSpec(mWidth,
View.MeasureSpec.EXACTLY), 0);
//动态定义高度
int height = mAppDetailDesTvDes.getMeasuredHeight();
if (isAnimator) {
//需要执行伸缩动画
if (isOpen) {
//收缩
mStart = height;
mEnd = get7Height();
//箭头向下动画
ObjectAnimator animator = ObjectAnimator.ofFloat(mAppDetailDesIvArrow,
"rotation",
-180,
0);
animator.setDuration(500);
animator.start();
} else {
//伸展
mStart = get7Height();
mEnd = height;
//箭头向上动画
ObjectAnimator animator = ObjectAnimator.ofFloat(mAppDetailDesIvArrow,
"rotation",
0,
180);
animator.setDuration(500);
animator.start();
}
//开始动画
startAnimation(mStart, mEnd);
isOpen = !isOpen;
} else {
//无需伸缩动画
ViewGroup.LayoutParams params = mAppDetailDesTvDes.getLayoutParams();
if (isOpen) {
//收缩
params.height = 0;
} else {
//伸展
params.height = height;
}
mAppDetailDesTvDes.setLayoutParams(params);
}
}
private int get7Height() {
TextView textView = new TextView(UiUtil.getContext());
textView.setText(mAppDetailDesTvDes.getText());
textView.setLines(7);
textView.measure(View.MeasureSpec.makeMeasureSpec(mWidth, View.MeasureSpec.EXACTLY),0);
return textView.getMeasuredHeight();
}
private void startAnimation(int start, int end) {
ValueAnimator animator = ValueAnimator.ofObject(new FloatEvaluator(), start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
ViewGroup.LayoutParams params = mAppDetailDesTvDes.getLayoutParams();
params.height = (int) animatedValue;
mAppDetailDesTvDes.setLayoutParams(params);
mAppDetailDesTvDes.invalidate();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//动画结束时,让ScrollView滚到最下面
//获取ScrollView
ViewParent parent = mAppDetailDesTvDes.getParent();
while (parent != null) {
parent = parent.getParent();
if (parent != null && parent instanceof ScrollView) {
//找到了
ScrollView scrollView = (ScrollView) parent;
scrollView.fullScroll(View.FOCUS_DOWN);
}
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.setDuration(500);
animator.start();
}
}
填充 DetailDesHolder的布局文件 item_app_detail_des.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="vertical"
android:padding="5dp">
<!-- 简介 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="简介"
android:textColor="@android:color/black"
android:textSize="16sp"/>
<!-- 描述详情区域 -->
<TextView
android:id="@+id/app_detail_des_tv_des"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="内容"
android:textColor="@android:color/darker_gray"
android:textSize="14sp"/>
<!-- 作者区域 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp">
<TextView
android:id="@+id/app_detail_des_tv_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="作者 : "
android:textColor="@android:color/darker_gray"
android:textSize="14sp"/>
<ImageView
android:id="@+id/app_detail_des_iv_arrow"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/arrow_down"/>
</RelativeLayout>
</LinearLayout>
</FrameLayout>
上面的只是文本伸缩部分的代码片段,仅供参考