package org.aisen.weibo.sina.ui.widget; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CollapsingToolbarLayout; import android.support.design.widget.TabLayout; import android.support.v7.widget.Toolbar; import android.util.AttributeSet; import android.view.View; import android.view.ViewParent; import android.widget.ImageView; import org.aisen.android.common.utils.BitmapUtil; import org.aisen.android.common.utils.Utils; import org.aisen.weibo.sina.R; /** * Created by wangdan on 16/2/4. */ public class ProfileCollapsingToolbarLayout extends CollapsingToolbarLayout { public static final String TAG = ProfileCollapsingToolbarLayout.class.getSimpleName(); private ImageView imgCover; private Toolbar toolbar; private TabLayout tabLayout; private AppBarLayout appBarLayout; private CollapsingToolbarLayout collapsingToolbarLayout; private View layDetail; private View layRealDetail; private View layName; private int statusbarHeight; private boolean scrimsShown; private Drawable mInsetForeground; private Rect mTempRect = new Rect(); private int verticalOffset; private boolean onCoverSet = false; private int appbarHeight; private int coverHeight;// 封面高度 private int avatarSize;// 头像尺寸 private int finalAvatarSize;// 缩小后的头像尺寸 private int avatarMarginLeft;// 头像左侧Margin private int avatarFinalMarginLeft;// 头像缩小后的Margin private Bitmap avatarBitmap;// 头像位图 private Matrix avatarMatrix;// 头像矩阵 private Bitmap layNameBitmap;// 包括名字、性别、认证三个要素的截图 private Matrix layNameMatrix; private int layNameMarginTop;// 名字顶部的margin private int layNameMarginLeft; private int finalLayNameSize; private float maxVerticalOffset;// Collapsing最大距离 public ProfileCollapsingToolbarLayout(Context context, AttributeSet attrs) { super(context, attrs); setup(context, attrs, 0); } public ProfileCollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setup(context, attrs, defStyleAttr); } private void setup(Context context, AttributeSet attrs, int defStyle) { statusbarHeight = getStatusBarHeight(); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProfileCollapsingToolbarLayout, defStyle, 0); if (a == null) { return; } mInsetForeground = a.getDrawable(R.styleable.ProfileCollapsingToolbarLayout_profileInsetForeground); a.recycle(); coverHeight = getResources().getDimensionPixelSize(R.dimen.profile_cover); avatarSize = Utils.dip2px(context, 100); finalAvatarSize = Utils.dip2px(context, 36); avatarFinalMarginLeft = Utils.dip2px(context, 16); layNameMarginTop = Utils.dip2px(context, 32); finalLayNameSize = Utils.dip2px(context, 28); layNameMarginLeft = Utils.dip2px(context, 12); avatarMarginLeft = getResources().getDimensionPixelSize(R.dimen.padding_normal); Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.user_placeholder); avatarBitmap = BitmapUtil.setImageCorner(sourceBitmap, sourceBitmap.getWidth()); } private void maybeSetup() { if (appBarLayout == null) { return; } // 将Cover的高度重新Measure一次 if (!onCoverSet && appBarLayout.getHeight() > 0) { onCoverSet = true; CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) imgCover.getLayoutParams(); lp.height = layDetail.getHeight() + coverHeight; imgCover.setLayoutParams(lp); imgCover.setPadding(imgCover.getPaddingLeft(), imgCover.getPaddingTop(), imgCover.getPaddingRight(), layDetail.getHeight()); } if (appbarHeight != appBarLayout.getHeight()) { appbarHeight = appBarLayout.getHeight(); // 计算Detail的layout_collapseParallaxMultiplier,使其收起来时刚好高度为ToolBar的高度 CollapsingToolbarLayout.LayoutParams params = (CollapsingToolbarLayout.LayoutParams) layDetail.getLayoutParams(); // 最大移动的距离 maxVerticalOffset = appBarLayout.getHeight() - (statusbarHeight + toolbar.getHeight() + tabLayout.getHeight()) - 2; // 计算移动后的top减去移动前的top就是需要offset,再用offset计算出multiplier float multiplier = ((maxVerticalOffset + statusbarHeight) - (collapsingToolbarLayout.getHeight() - layDetail.getHeight())) * 1.0f / maxVerticalOffset; if (params.getParallaxMultiplier() != multiplier) { params.setParallaxMultiplier(multiplier); } avatarMatrix = new Matrix(); setNameBitmap(); } } private void setNameBitmap() { if (layName == null) return; layNameBitmap = Bitmap.createBitmap(layName.getWidth(), layName.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(layNameBitmap); layName.draw(canvas); layName.setVisibility(View.INVISIBLE); layNameMatrix = new Matrix(); } public void resetNameBitmap() { layName.setVisibility(View.VISIBLE); onCoverSet = false; layNameBitmap = null; } public void setAvatarBitmap(Bitmap bitmap) { avatarBitmap = BitmapUtil.setImageCorner(bitmap, bitmap.getWidth()); innerOffsetChangedListener.onOffsetChanged(appBarLayout, verticalOffset); invalidate(); } @Override public void setScrimsShown(boolean shown, boolean animate) { super.setScrimsShown(shown, animate); scrimsShown = shown; } private boolean isScrimsShown() { return scrimsShown; } @Override public void draw(Canvas canvas) { super.draw(canvas); if (avatarMatrix != null) { final int saveCount = canvas.save(); if (!isScrimsShown()) { mTempRect.set(0, -verticalOffset, getWidth(), statusbarHeight + -verticalOffset); mInsetForeground.setBounds(mTempRect); mInsetForeground.draw(canvas); } if (layNameBitmap != null) { canvas.drawBitmap(layNameBitmap, layNameMatrix, null); } canvas.drawBitmap(avatarBitmap, avatarMatrix, null); canvas.restoreToCount(saveCount); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); // Add an OnOffsetChangedListener if possible final ViewParent parent = getParent(); if (parent instanceof AppBarLayout) { ((AppBarLayout) parent).addOnOffsetChangedListener(innerOffsetChangedListener); layDetail = findViewById(R.id.layDetail); layRealDetail = findViewById(R.id.layRealDetail); toolbar = (Toolbar) findViewById(R.id.toolbar); appBarLayout = (AppBarLayout) parent; collapsingToolbarLayout = this; imgCover = (ImageView) findViewById(R.id.imgCover); tabLayout = (TabLayout) appBarLayout.findViewById(R.id.tabLayout); layName = findViewById(R.id.layName); } } @Override protected void onDetachedFromWindow() { // Remove our OnOffsetChangedListener if possible and it exists final ViewParent parent = getParent(); if (parent instanceof AppBarLayout) { ((AppBarLayout) parent).removeOnOffsetChangedListener(innerOffsetChangedListener); } super.onDetachedFromWindow(); } private AppBarLayout.OnOffsetChangedListener innerOffsetChangedListener = new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { maybeSetup(); if (layNameBitmap == null) { setNameBitmap(); } ProfileCollapsingToolbarLayout.this.verticalOffset = verticalOffset; // offset移动的比例 float factor = -verticalOffset * 1.0f / maxVerticalOffset; if (avatarMatrix != null) { // 从avatarSize变化到finalAvatarSize,是根据这个factor逐渐变化的,计算它的dsize变化值 float dsize = (avatarSize - finalAvatarSize) * factor; // 计算现在需要显示的avatar尺寸 float avatarToSize = avatarSize - dsize; // 缩放 float scale = avatarToSize * 1.0f / avatarBitmap.getWidth(); avatarMatrix.setScale(scale, scale); // 初始化Top float startAvatarTop = getHeight() - layDetail.getHeight() - avatarToSize * 3.0f / 4; // 最终显示的Top float toAvatartTop = maxVerticalOffset + statusbarHeight + (toolbar.getHeight() - finalAvatarSize) * 1.0f / 2; float avatarTop = startAvatarTop - (startAvatarTop - toAvatartTop) * factor; // 初始化MarginLeft float startMargin = avatarMarginLeft; float toMargin = avatarFinalMarginLeft; float margin = startMargin - (startMargin - toMargin) * factor; // 平移 avatarMatrix.postTranslate(margin, avatarTop); } if (layNameMatrix != null) { float dsize = (layNameBitmap.getHeight() - finalLayNameSize) * factor; float nameToSize = layNameBitmap.getHeight() - dsize; float scale = nameToSize * 1.0f / layNameBitmap.getHeight(); layNameMatrix.setScale(scale, scale); float startNameTop = getHeight() - layDetail.getHeight() + layNameMarginTop; float toNameTop = maxVerticalOffset + statusbarHeight + (toolbar.getHeight() - finalLayNameSize) * 1.0f / 2; float nameTop = startNameTop - (startNameTop - toNameTop) * factor; float startMargin = avatarMarginLeft; float toMargin = avatarFinalMarginLeft + finalAvatarSize + layNameMarginLeft; float margin = startMargin - (startMargin - toMargin) * factor; layNameMatrix.postTranslate(margin, nameTop); } if (layRealDetail != null) { layRealDetail.setAlpha(1.0f - factor * 0.7f); } } }; public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } }