最近项目有个我的相册功能,类似于qq空间的效果,整理下代码分享给大家。
1、重写ScrollView(其他类似ListView,recycleView类似),类文件如下(注意:我是因为布局原因,在类里面定义了两个缩放View,如无特殊要求一个就可以了,而且禁止了宽度的缩放,只允许竖直缩放,大家有新需求可以修改)
/**
* 阻尼效果的scrollview
*/
public class DampScrollView extends ScrollView {
public DampScrollView(Context context) {
super(context);
}
public DampScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DampScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// 用于记录下拉位置
private float y = 0f;
// zoomView原本的宽高
private int zoomViewWidth = 0;
private int zoomViewHeight = 0;
private int layoutWidth = 0;
private int layoutHeight = 0;
//上拉的距离
private int distance;
// 是否正在放大
private boolean mScaling = false;
// 放大的view,默认为第一个子view
private View zoomView;
private View layout;
public void setZoomView(View zoomView, View layout) {
this.zoomView = zoomView;
this.layout = layout;
}
// 滑动放大系数,系数越大,滑动时放大程度越大
private float mScaleRatio = 0.4f;
public void setmScaleRatio(float mScaleRatio) {
this.mScaleRatio = mScaleRatio;
}
// 最大的放大倍数
private float mScaleTimes = 2f;
public void setmScaleTimes(int mScaleTimes) {
this.mScaleTimes = mScaleTimes;
}
// 回弹时间系数,系数越小,回弹越快
private float mReplyRatio = 0.5f;
public void setmReplyRatio(float mReplyRatio) {
this.mReplyRatio = mReplyRatio;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 不可过度滚动,否则上移后下拉会出现部分空白的情况
setOverScrollMode(OVER_SCROLL_NEVER);
// 获得默认第一个view
if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && zoomView == null) {
ViewGroup vg = (ViewGroup) getChildAt(0);
if (vg.getChildCount() > 0) {
zoomView = vg.getChildAt(0);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (zoomViewWidth <= 0 || zoomViewHeight <= 0) {
zoomViewWidth = zoomView.getMeasuredWidth();
zoomViewHeight = zoomView.getMeasuredHeight();
layoutWidth = layout.getMeasuredWidth();
layoutHeight = layout.getMeasuredHeight();
}
if (zoomView == null || zoomViewWidth <= 0 || zoomViewHeight <= 0) {
return super.onTouchEvent(ev);
}
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (!mScaling) {
if (getScrollY() == 0) {
y = ev.getY();//滑动到顶部时,记录位置
} else {
break;
}
}
distance = (int) ((ev.getY() - y) * mScaleRatio);
if (distance < 0) break;//若往下滑动
mScaling = true;
setZoom(distance);
return true;
case MotionEvent.ACTION_UP:
mScaling = false;
replyView();
break;
}
return super.onTouchEvent(ev);
}
/**
* 放大view
*/
private void setZoom(float s) {
float scaleTimes = (float) ((zoomViewWidth + s) / (zoomViewWidth * 1.0));
// 如超过最大放大倍数,直接返回
if (scaleTimes > mScaleTimes) return;
ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
ViewGroup.LayoutParams layoutParams1 = layout.getLayoutParams();
//layoutParams.width = (int) (zoomViewWidth + s);
layoutParams.height = (int) (zoomViewHeight * ((zoomViewWidth + s) / zoomViewWidth));
layoutParams1.height = (int) (layoutHeight * ((layoutWidth + s) / layoutWidth));
// 设置控件水平居中
//((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - zoomViewWidth) / 2, 0, 0, 0);
zoomView.setLayoutParams(layoutParams);
layout.setLayoutParams(layoutParams1);
if (s > zoomViewHeight / 3.0) {
if (refreshListerer != null)
refreshListerer.startRefresh();
}
}
/**
* 回弹
*/
private void replyView() {
if (refreshListerer != null)
if (distance > zoomViewHeight / 3.0)
refreshListerer.getData();
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (onScrollListener != null) onScrollListener.onScroll(l, t, oldl, oldt);
}
private OnScrollListener onScrollListener;
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
private RefreshListerer refreshListerer;
public void setRefreshListener(RefreshListerer refreshListerer) {
this.refreshListerer = refreshListerer;
}
/**
* 滑动监听
*/
public interface OnScrollListener {
void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY);
}
/**
* 刷新监听
*/
public interface RefreshListerer {
void startRefresh();
void getData();
}
/**
* 开启回弹动画
*/
public void startAntimation() {
final float distance = zoomView.getMeasuredHeight() - zoomViewHeight;
// 设置动画
ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setZoom((Float) animation.getAnimatedValue());
}
});
anim.start();
}
}
2、主Activity代码如下
public class MyPhotoActivity extends BaseActivity implements DampScrollView.RefreshListerer {
private DampScrollView scroll_view;
private RoundedImageView imageView;
private RelativeLayout root, relative;
private MyListView listView;
private MyPhotoAdapter adapter;
private TitleBarBuilder builder;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.my_photo);
initTitleBar();
initView();
monitor();
}
private void initTitleBar() {
builder = new TitleBarBuilder(this);
builder.setTitle("我的相册").setAlpha(0).setImageLeftRes(R.mipmap.back).setLeftListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
}).setImageRightRes(R.mipmap.btn_add).setRightListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ToastUtils.showShort(MyPhotoActivity.this, "右边操作");
}
});
}
private void initView() {
scroll_view = (DampScrollView) findViewById(R.id.scroll_view);
scroll_view.setRefreshListener(this);
root = (RelativeLayout) findViewById(R.id.root);
imageView = (RoundedImageView) findViewById(R.id.imageView);
listView = (MyListView) findViewById(R.id.listView);
relative = (RelativeLayout) findViewById(R.id.relative);
scroll_view.setZoomView(imageView, relative);
adapter = new MyPhotoAdapter(this);
listView.setAdapter(adapter);
}
@Override
protected void onResume() {
super.onResume();
root.setFocusable(true);
root.setFocusableInTouchMode(true);
root.requestFocus();
}
private void monitor() {
scroll_view.setOnScrollListener(new DampScrollView.OnScrollListener() {
@Override
public void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollY < 500) {
float alpha = ((float) scrollY) / 500;
builder.setAlpha(alpha);
} else {
builder.setAlpha(1);
}
}
});
}
@Override
public void startRefresh() {
builder.setProgress(View.VISIBLE);
}
Handler handler = new Handler();
@Override
public void getData() {
//模拟请求数据
handler.postDelayed(new Runnable() {
@Override
public void run() {
builder.setProgress(View.GONE);
}
}, 2000);
scroll_view.startAntimation();
}
}
3、TitleBarBuilder是我项目里面的一个获取标题布局id的工具类,大家也可以在activity获取控件id,代码如下
public class TitleBarBuilder {
protected RelativeLayout leftLayout, root;
protected ImageView leftImage;
private TextView leftTv;
protected RelativeLayout rightLayout;
protected ImageView rightImage;
private TextView rightTv;
protected TextView titleView;
protected RelativeLayout titleLayout;
private ProgressBar progressbar;
public TitleBarBuilder(Activity context) {
root = (RelativeLayout) context.findViewById(R.id.root);
leftLayout = (RelativeLayout) context.findViewById(R.id.left_layout);
leftImage = (ImageView) context.findViewById(R.id.left_image);
leftTv = (TextView) context.findViewById(R.id.left_tv);
rightLayout = (RelativeLayout) context.findViewById(R.id.right_layout);
rightImage = (ImageView) context.findViewById(R.id.right_image);
rightTv = (TextView) context.findViewById(R.id.right_tv);
titleView = (TextView) context.findViewById(R.id.title);
progressbar = (ProgressBar) context.findViewById(R.id.progressbar);
titleLayout = (RelativeLayout) context.findViewById(R.id.root);
}
public TitleBarBuilder(View context) {
root = (RelativeLayout) context.findViewById(R.id.root);
leftLayout = (RelativeLayout) context.findViewById(R.id.left_layout);
leftImage = (ImageView) context.findViewById(R.id.left_image);
leftTv = (TextView) context.findViewById(R.id.left_tv);
rightLayout = (RelativeLayout) context.findViewById(R.id.right_layout);
rightImage = (ImageView) context.findViewById(R.id.right_image);
rightTv = (TextView) context.findViewById(R.id.right_tv);
titleView = (TextView) context.findViewById(R.id.title);
titleLayout = (RelativeLayout) context.findViewById(R.id.root);
progressbar = (ProgressBar) context.findViewById(R.id.progressbar);
}
public TitleBarBuilder setTitle(String str) {
titleView.setText(str);
return this;
}
public TitleBarBuilder setTextLeft(String str) {
leftTv.setVisibility(View.VISIBLE);
leftLayout.setVisibility(View.VISIBLE);
leftTv.setText(str);
return this;
}
public TitleBarBuilder setTextRight(String str) {
rightTv.setVisibility(View.VISIBLE);
rightLayout.setVisibility(View.VISIBLE);
rightTv.setText(str);
return this;
}
public TitleBarBuilder setImageLeftRes(int res) {
leftImage.setVisibility(View.VISIBLE);
leftLayout.setVisibility(View.VISIBLE);
leftImage.setImageResource(res);
return this;
}
public TitleBarBuilder setImageRightRes(int res) {
rightImage.setVisibility(View.VISIBLE);
rightLayout.setVisibility(View.VISIBLE);
rightImage.setImageResource(res);
return this;
}
public TitleBarBuilder setLeftListener(View.OnClickListener listener) {
if (leftTv.getVisibility() == View.VISIBLE || leftImage.getVisibility() == View.VISIBLE) {
leftLayout.setOnClickListener(listener);
}
return this;
}
public TitleBarBuilder setRightListener(View.OnClickListener listener) {
if (rightTv.getVisibility() == View.VISIBLE || rightImage.getVisibility() == View.VISIBLE) {
rightLayout.setOnClickListener(listener);
}
return this;
}
public TitleBarBuilder setTitleBarBackGround(int res) {
root.setBackgroundResource(res);
return this;
}
public TitleBarBuilder setAlpha(float alpha){
root.getBackground().setAlpha((int)(alpha*255));
return this;
}
public TitleBarBuilder setProgress(int visibility){
progressbar.setVisibility(visibility);
return this;
}
}
4、titlebar的布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/gradient_bg"
android:paddingTop="10dp"
android:gravity="center_vertical">
<RelativeLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:layout_centerVertical="true"
android:background="@drawable/ease_common_tab_bg"
android:clickable="true">
<TextView
android:id="@+id/left_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="invisible" />
<ImageView
android:id="@+id/left_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerInside"
/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:clickable="true">
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_toLeftOf="@+id/title"
android:visibility="gone"
android:indeterminate="false"
android:indeterminateDrawable="@drawable/progressbar" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="8dp"
android:layout_centerVertical="true"
android:background="@drawable/ease_common_tab_bg">
<TextView
android:id="@+id/right_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="invisible" />
<ImageView
android:id="@+id/right_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerInside" />
</RelativeLayout>
</RelativeLayout>
5、主Activity布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<com.qcwl.debo.view.DampScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.qcwl.debo.view.RoundedImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@mipmap/wish_star_bg"
android:scaleType="centerCrop"
app:mutate_background="false"
app:oval="false" />
</LinearLayout>
<RelativeLayout
android:id="@+id/relative"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_marginTop="100dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/sign"
android:layout_below="@+id/imageView"
android:layout_marginBottom="25dp"
android:layout_toLeftOf="@+id/image"
android:text="洛神"
android:textColor="@android:color/black"
android:textSize="16sp" />
<com.qcwl.debo.view.RoundedImageView
android:id="@+id/image"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_above="@+id/sign"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="15dp"
android:scaleType="centerCrop"
android:src="@mipmap/em_default_avatar"
app:border_color="@android:color/white"
app:border_width="2dp"
app:corner_radius="5dip"
app:mutate_background="false"
app:oval="true" />
<TextView
android:id="@+id/sign"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:paddingBottom="10dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="140dp"
android:layout_marginRight="15dp"
android:gravity="right"
android:text="偏弱蛟龙,宛若游龙,仿佛兮若青云之蔽月,飘摇兮若流风之回雪"
android:textColor="@android:color/black"
android:textSize="12sp" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
<com.qcwl.debo.view.MyListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.qcwl.debo.view.DampScrollView>
<include layout="@layout/title_bar" />
</FrameLayout>
RoundedImageView 是我自定义的控件,换成普通ImageView就可以了
6、下面附上效果图
7、如遇项目资源报错,一般是资源文件,换成自己的或者系统的就可以了,上图效果为沉浸式,别忘记在activity加入沉浸式,效果好一些
/**
* 沉浸式状态栏
*/
private void initState() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
在activity的onCreate方法加入就可以。