public class EyeView extends FrameLayout {
private Paint paint;
private Bitmap bitmap;
public EyeView(Context context) {
super(context);
init();
}
public EyeView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public EyeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
@SuppressLint("NewApi")
private void init() {
setDrawingCacheEnabled(true);
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (bitmap != null) {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(bitmap, 0, 0, paint);
paint.setXfermode(null);
}
}
public void setRadius(int radius) {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, paint);
invalidate();
}
}
public class PullLayout extends ScrollView {
private View rl_top;
private View ll_weather;
private View ll_content;
private TextView tv;
private EyeView ev;
private ObjectAnimator oa;
private float lastY = -1;
private float detalY = -1;
private int range;
private int tvHeight;
private int tvWidth;
private boolean isTouchOrRunning;
private boolean isActionCancel;
public PullLayout(Context context) {
super(context);
}
public PullLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PullLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setVerticalScrollBarEnabled(false);
rl_top = findViewById(R.id.rl_top);
ll_content = findViewById(R.id.ll_content);
tv = (TextView) findViewById(R.id.tv);
ev = (EyeView) findViewById(R.id.ev);
ll_weather = findViewById(R.id.ll_weather);
rl_top.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
rl_top.getViewTreeObserver().removeGlobalOnLayoutListener(this);
range = rl_top.getHeight();
scrollTo(0, range);
rl_top.getLayoutParams().height = range;
}
});
tv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
tvHeight = tv.getHeight();
tvWidth = tv.getWidth();
ViewHelper.setTranslationY(ll_content, tvHeight);
}
});
ev.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
close();
}
});
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
open();
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
isActionCancel = false;
isTouchOrRunning = true;
lastY = ev.getY();
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (oa != null && oa.isRunning()) {
ev.setAction(MotionEvent.ACTION_UP);
isActionCancel = true;
}
if (isActionCancel && ev.getAction() != MotionEvent.ACTION_DOWN) {
return false;
}
if (ev.getActionIndex() != 0 && getScrollY() < range) {
ev.setAction(MotionEvent.ACTION_UP);
isActionCancel = true;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
isTouchOrRunning = true;
if (getScrollY() != 0) {
detalY = 0;
lastY = ev.getY();
} else {
detalY = ev.getY() - lastY;
if (detalY > 0) {
setT((int) -detalY / 5);
return true;
}
}
break;
case MotionEvent.ACTION_UP:
isTouchOrRunning = false;
if (getScrollY() < range) {
if (detalY != 0) {
reset();
} else {
toggle();
}
return true;
}
break;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (t > range) {
return;
} else if (!isTouchOrRunning && t != range) {
scrollTo(0, range);
} else {
animateScroll(t);
}
}
public void setT(int t) {
scrollTo(0, t);
if (t < 0) {
animatePull(t);
}
}
private void animateScroll(int t) {
float percent = (float) t / range;
ViewHelper.setTranslationY(rl_top, t);
ViewHelper.setTranslationY(ll_content, tvHeight * percent);
ViewHelper.setScaleX(tv, 2 - percent);
ViewHelper.setScaleY(tv, 2 - percent);
ViewHelper.setTranslationX(tv, tvWidth * (1 - percent) / 2f);
ViewHelper.setTranslationY(tv, t + tvHeight * (1 - percent) / 2f);
ViewHelper.setTranslationY(ev, -t / 2);
ViewHelper.setTranslationY(ll_weather, -t / 2);
ev.setRadius((int) (range * 0.25f * (1 - percent)));
tv.setTextColor(evaluate(percent, Color.WHITE, Color.BLACK));
}
private void animatePull(int t) {
rl_top.getLayoutParams().height = range - t;
rl_top.requestLayout();
float percent = (float) t / range;
ViewHelper.setScaleX(ev, 1 - percent);
ViewHelper.setScaleY(ev, 1 - percent);
ViewHelper.setScaleX(tv, 2 - percent);
ViewHelper.setScaleY(tv, 2 - percent);
ViewHelper.setTranslationX(tv, tvWidth * (1 - percent) / 2f);
ViewHelper.setTranslationY(ll_weather, t / 2);
}
private Integer evaluate(float fraction, Object startValue, Integer endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
| (int) ((startB + (int) (fraction * (endB - startB))));
}
public void toggle() {
if (isOpen()) {
close();
} else {
open();
}
}
private Status status;
public enum Status {
Open, Close;
}
public boolean isOpen() {
return status == Status.Open;
}
private void reset() {
if (oa != null && oa.isRunning()) {
return;
}
oa = ObjectAnimator.ofInt(this, "t", (int) -detalY / 5, 0);
oa.setDuration(150);
oa.start();
}
public void close() {
if (oa != null && oa.isRunning()) {
return;
}
oa = ObjectAnimator.ofInt(this, "t", getScrollY(), range);
oa.setInterpolator(new DecelerateInterpolator());
oa.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator arg0) {
isTouchOrRunning = true;
}
@Override
public void onAnimationRepeat(Animator arg0) {
}
@Override
public void onAnimationEnd(Animator arg0) {
isTouchOrRunning = false;
status = Status.Close;
}
@Override
public void onAnimationCancel(Animator arg0) {
}
});
oa.setDuration(250);
oa.start();
}
public void open() {
if (oa != null && oa.isRunning()) {
return;
}
oa = ObjectAnimator.ofInt(this, "t", getScrollY(), (int) (-getScrollY() / 2.2f), 0);
oa.setInterpolator(new DecelerateInterpolator());
oa.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator arg0) {
isTouchOrRunning = true;
}
@Override
public void onAnimationRepeat(Animator arg0) {
}
@Override
public void onAnimationEnd(Animator arg0) {
isTouchOrRunning = false;
status = Status.Open;
}
@Override
public void onAnimationCancel(Animator arg0) {
}
});
oa.setDuration(400);
oa.start();
}
}
<com.bluemor.pulllayout.PullLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="@+id/rl_top"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/weather_bg_rain" />
<com.bluemor.pulllayout.EyeView
android:id="@+id/ev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="30dp"
android:background="@drawable/selector_bg" >
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/eye" />
</com.bluemor.pulllayout.EyeView>
<LinearLayout
android:id="@+id/ll_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:layout_marginLeft="30dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/weather_mostly_cloudy"
android:gravity="center"
android:text="10°~17°\r\n星期三"
android:textColor="@android:color/white"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:drawableTop="@drawable/weather_drizzle"
android:gravity="center"
android:text="11°~18°\r\n星期四"
android:textColor="@android:color/white"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout>
<FrameLayout
android:id="@+id/fl_bottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/rl_top"
android:background="#F4F4F4" >
<LinearLayout
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="50dp"
android:paddingTop="10dp" >
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/clip" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/clip2" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/clip2" />
</LinearLayout>
</FrameLayout>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginTop="10dp"
android:background="@drawable/selector_bg"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:text="BlueMor"
android:textSize="25sp" />
</RelativeLayout>
</com.bluemor.pulllayout.PullLayout>原文:http://blog.csdn.net/u014600432/article/details/42105809