曲木为直终必弯,养狼当犬看家难。墨染鸬鹚黑不久,粉刷乌鸦白不坚。蜜饯黄莲终需苦,强摘瓜果不能甜。好事总得善人做,哪有凡人做神仙。
当!
废话不多言,上回书说道,我最近寻思干点嘛,却又无所事事,天天水群,于是心不安理不得,这天忽然看到一个画廊效果,虽然已是过时产物,但是本着劳资不会,就是比比的崇高目标,结果遭人鄙视,无人同情,令人叹惋。
于是乎,奋笔疾书,瞎(说鸡不说吧,文明你我他)写,终于在某年某月某时某分拼凑出来,效果如下:
因为做的是本地图片加载的画廊效果,在加载网络图片时会有一定的闪屏,文末也会给大家提供解决方法,但本例写的时候开始使用的是本地图片。
首先我们拿到布局,应该想到,上面的大图应该是一个ImageView,而下面是一个可横向滑动View,因为横向滑动的View并没有多少选择,所以这里我选择了recyclerView,这里看基本的布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<test.com.xiaomamenu.RectImageView
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="200dp"
android:transitionName="translate"
android:id="@+id/second_img"
android:layout_margin="30dp"
android:scaleType="centerCrop"
/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/second_rv"
></android.support.v7.widget.RecyclerView>
</LinearLayout>
</FrameLayout>
这个RectImageView继承了ImageView,在onmeaure的时候使高度和宽度相等,这个非常简单,这里就不提了,实在不会的可以使用ImageView高度宽度相等即可。
这里应该注意一点,最外层的view必须是FrameLayout,因为我们后面会根据FrameLayout的特性进行动画的操作。
接下来,我们定义一个RecyclerView的Adapter,这里只是代码演示,所以代码比较粗糙,勿怪。
rv.setLayoutManager(new LinearLayoutManager(SecondActivity.this, LinearLayoutManager.HORIZONTAL, false));
rv.setAdapter(new RecyclerView.Adapter<SecondActivity.VH>() {
@Override
public SecondActivity.VH onCreateViewHolder(ViewGroup parent, int viewType) {
return new SecondActivity.VH(LayoutInflater.from(SecondActivity.this).inflate(R.layout.new_item, parent, false));
}
@Override
public void onBindViewHolder(final SecondActivity.VH holder, final int position) {
//holder.img.setImageResource(imgs.get(position));
Glide.with(SecondActivity.this).load(imgs.get(position)).dontAnimate().dontTransform().diskCacheStrategy(DiskCacheStrategy.ALL).into(holder.img);
}
@Override
public int getItemCount() {
return imgs.size();
}
});
这样我们非常质朴的Adapter就写出来了,首先我们根据图片应该联想到,两张图片对换,那么我们肯定需要list 和 大图资源数据的对换,这样我们需要一个变量来解决这个问题。
接下来我们开始构造方法,首先我希望可以通过单例的形式实现点击的时候动画交互效果,这样能有效的节约资源和内存,那么首先我们先无脑new出来一个utils先。
public class AnimatorUtils<T> {
private static AnimatorUtils utils;
public static AnimatorUtils getInstance() {
if (null == utils) {
synchronized (AnimatorUtils.class) {
if (null == utils) {
utils = new AnimatorUtils();
}
}
}
return utils;
}
}
这样我们构造出了一个单例模式,然后我们开始写具体的方法,首先我们肯定需要知道和我们交互的itemView和ImageView,然后我们还需要context上下文来获取根布局以及一些其他的操作,还有List数据,当前itemView的position位置,以及大图的资源文件,因为大图的资源文件未知,所以我这里使用了泛型,我们大概就只需要这么多的参数,好了,接下来开始大段的代码,代码上都写了注释,所以应该很容易理解。
//获取当前activity下的根布局
ViewGroup vp= (ViewGroup) ((Activity)context).findViewById(android.R.id.content);
ViewGroup rootView = (ViewGroup) vp.getChildAt(0);
if (!((rootView instanceof RelativeLayout) || (rootView instanceof FrameLayout))) {
throw new IllegalArgumentException("关掉重试,换换运气");
}
//获取target的宽高
translateViewWidth = translateView.getWidth();
translateViewHeight = translateView.getHeight();
if (translateViewWidth <= 0 || translateViewHeight <= 0) {
throw new IllegalArgumentException("建议你删代码跑路");
}
//获取itemView的宽高
itemWidth = itemView.getWidth();
itemHeight = itemView.getHeight();
if (itemWidth <= 0 || itemHeight <= 0) {
throw new IllegalArgumentException("我已经删掉了android studio");
}
//获取itemView所在的位置
itemView.getLocationInWindow(itemViewLocation);
//获取target所在位置
translateView.getLocationInWindow(translateViewLocation);
//获取状态栏高度
int statusHeight = getStatusHeight();
不要在意我throw错误的那些细节,那些都只是我痛苦血泪之后的真实。
我们获取了一些必要的参数,比如当前itemView和ImageView在window中的位置,这样才能做动画的参数值,但是该怎么样做动画呢,首先属性动画虽然能改变view的属性,但是并不能改变view在当前层级的位置,所以我们并不能直接操作itemView和ImageView,这样我们就只剩下一条路了,造假!
于是乎,乎如是,一个又low又2又弱鸡的方案就诞生了。
//第一次add进来
if (translateViewBitmap == null) {
translateViewBitmap = new ImageView(context);
rootView.addView(translateViewBitmap);
lp2 = (FrameLayout.LayoutParams) translateViewBitmap.getLayoutParams();
if (lp2 != null) {
lp2.width = translateViewWidth;
lp2.height = translateViewHeight;
lp2.setMargins(translateViewLocation[0], translateViewLocation[1] - statusHeight, 0, 0);
} else {
lp2 = new FrameLayout.LayoutParams(translateViewWidth, translateViewHeight);
lp2.setMargins(translateViewLocation[0], translateViewLocation[1] - statusHeight, 0, 0);
}
translateViewBitmap.setLayoutParams(lp2);
} else {
translateViewBitmap.setVisibility(View.VISIBLE);
translateViewBitmap.setScaleX(1);
translateViewBitmap.setScaleY(1);
translateViewBitmap.setTranslationX(0);
translateViewBitmap.setTranslationY(0);
lp2