編輯:關於Android編程
下面我們把這個控件內嵌到Layout中做一些動畫和展示,效果圖:

這個子控件可以上下移動,可以左右滑動,如果上下滑動距離大於左右滑動距離,則必須上下滑動<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+1eLR+cC00LRvblRvdWNoysK8/jo8L3A+CjxwPjxwcmUgY2xhc3M9"brush:java;"> @Override
public boolean onTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
int mScrollX = this.getScrollX();
final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mFlagLimitMove = false;
mFlagLimitUp = false;
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mOriMotionX = x;
mOriMotionY = y;
mLastMotionX = x;
mLastMotionY = y;
mTimeDown = System.currentTimeMillis();
mLastDownX = x;
return true;
case MotionEvent.ACTION_MOVE:
//如果是往後滑動,屏幕向前,那麼mLastMotionX是比x大的,deltaX是正的
int deltaX = (int) (mLastMotionX - x);
int deltaY = (int) (mLastMotionY - y);
// final int moveX = (int) (mOriMotionX - x);
final int moveY = (int) (mOriMotionY - y);
mLastMotionX = x;
mLastMotionY = y;
//X方向的移動更多
if (Math.abs(deltaY) < Math.abs(deltaX)) {
//雖然X方向移動更多,但由於已經判定為上下滑動,所以只能return true,做這種情況左右不能滑動
if (mFlagLimitUp) {
return true;
}
final int buffer = getWidth() / 2;
if (deltaX < 0) {
if (deltaX < -MOVEY_NUM_X) {
//mFlagLimitMove代表X方向確認在滑動了
mFlagLimitMove = true;
}
if (mCurrentScreen == 0 && !mExecuteWhileSnapOut) {
System.out.println("=====deltaX="+deltaX);
deltaX = getSlowDownDelta(deltaX);
System.out.println("=====after deltaX="+deltaX);
}
System.out.println("====mScrollX="+mScrollX+"buffer="+buffer+"deltaX="+deltaX+"x="+(Math.max(-mScrollX - buffer, deltaX)));
scrollBy(Math.max(-mScrollX - buffer, deltaX), 0);
// }
} else if (deltaX > 0) {
int availableToScroll = 0;
if (getChildCount() > 0) { //此時Workspace上可能未加任何item,count == 0
availableToScroll = getChildAt(
getChildCount() - 1).getRight()
- mScrollX - getWidth();
}
if (deltaX > MOVEY_NUM_X) {
mFlagLimitMove = true;
}
if (mCurrentScreen == getChildCount() - 1 && !mExecuteWhileSnapOut) {
deltaX = getSlowDownDelta(deltaX);
}
System.out.println("====availableToScroll="+availableToScroll+"deltaX="+deltaX);
scrollBy(Math.min(availableToScroll + buffer, deltaX), 0);
}
} else {
//如果已經判定為上下滑動或 ,當時X方向也有移動,這種情況也不處理
if (mFlagLimitMove || mFlagLimitUp) {
return true;
}
//deltaY>0說明為往上滑動
if (deltaY > 0 && moveY > MOVEY_NUM) {
if (mHandler != null) {
mFlagLimitUp = true;
mHandler.sendMessage(mHandler
.obtainMessage(DingLayout.MESSAGE_MOVING_UP));
}
} else if (deltaY < 0 && moveY < -MOVEY_NUM) {
if (mHandler != null) {
mFlagLimitUp = true;
mHandler.sendMessage(mHandler
.obtainMessage(DingLayout.MESSAGE_MOVING_DOWN));
}
}
}
return true;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(DEFAULT_VALUE,
mMaximumVelocity);
int velocityX = (int) velocityTracker.getXVelocity();
int velocityY = (int) velocityTracker.getYVelocity();
System.out.println("====mFlagLimitUp="+mFlagLimitUp+"mFlagLimitMove="+mFlagLimitMove);
if (!mFlagLimitUp) {
if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
// Fling hard enough to move left
snapToScreen(mCurrentScreen - 1);
} else if (velocityX < -SNAP_VELOCITY
&& mCurrentScreen < getChildCount() - 1) {
// Fling hard enough to move right
snapToScreen(mCurrentScreen + 1);
} else {
snapToDestination(mLastMotionX < mOriMotionX);
}
} else {
snapToDestination(mLastMotionX < mOriMotionX);
}
mTimeUp = System.currentTimeMillis();
//如果x方向移動非常少,並且沒有y方向的移動,我們來判斷是不是點擊事件
if (!mFlagLimitUp && !mFlagLimitMove) {
// 如果點擊時間比較短,而且手指沒有移動很大位置,則認為為點擊事件
if (Math.abs(x - mOriMotionX) < MOVE_LIMIT
&& Math.abs(y - mOriMotionY) < MOVE_LIMIT
&& Math.abs(mTimeUp - mTimeDown) < TIME_LIMIT) {
if (mHandler != null) {
mHandler.sendMessage(mHandler.obtainMessage(
DingLayout.MESSAGE_MOVING_CLICK, y));
return true;
}
}
if (velocityY > Y_RATE_LIMIT
&& Math.abs(velocityX) < X_RATE_LIMIT) {
if (mHandler != null) {
mHandler.sendMessage(mHandler
.obtainMessage(DingLayout.MESSAGE_MOVING_DOWN));
}
} else if (velocityY < -Y_RATE_LIMIT
&& Math.abs(velocityX) < X_RATE_LIMIT) {
if (mHandler != null) {
mHandler.sendMessage(mHandler
.obtainMessage(DingLayout.MESSAGE_MOVING_UP));
}
}
} // end flag
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
mFlagLimitMove = false;
mFlagLimitUp = false;
mTouchState = TOUCH_STATE_REST;
if (Math.abs(mLastDownX - x) > TEN) {
return true;
}
return false;
case MotionEvent.ACTION_CANCEL:
mTouchState = TOUCH_STATE_REST;
return false;
default:
break;
}
return true;
}
activity:
布局:
public class DingLayoutActivity extends Activity implements
OnViewChangedListener {
DingLayout mDingLayout;
Workspace mWorkspace;
/** 用inflater來載入layout. */
private LayoutInflater mInflater;
int mTotalDingnum;
ImageView mBtnRefresh;
private int mCurrentDownUrlIndex = 0;
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main1);
mDingLayout = (DingLayout) findViewById(R.id.dinglayout);
mDingLayout.setHandlerFormActivity(this.mHandler);
mWorkspace = (Workspace) findViewById(R.id.workspace);
mWorkspace.setOnViewChangedListener(this);
initialWorkspace();
}
/**
* 初始化workspace.
*/
private void initialWorkspace() {
mInflater = LayoutInflater.from(this);
// 該list為內存中的ding列表,列表中元素存儲著ding的A部分數據
DingManager dingMgr = DingManager.getInstance(this);
List list = dingMgr.getDingList();
mTotalDingnum = list.size();
// 遍歷列表中的各個元素來構造workspace中的view
for (int i = 0; i < mTotalDingnum; i++) {
View view = mInflater.inflate(R.layout.ding_item, null);
DingInfo info = list.get(i);
view.setTag(info.getDingId());
String oldContent = info.getContent();
mWorkspace.addView(view);
mBtnRefresh = (ImageView) view.findViewById(R.id.btn_refresh);
setViewData(info, view, true);
info.setContent(oldContent);
// end modify
}
mDingLayout.updateDots(mTotalDingnum, mCurrentDownUrlIndex);
}
private void setViewData(DingInfo netdingdata, View view, boolean useTitle) {
if (view == null) {
return;
}
TextView title = (TextView) view.findViewById(R.id.title);
TextView content = (TextView) view.findViewById(R.id.main_content);
TextView description = (TextView) view.findViewById(R.id.description);
TextView time = (TextView) view.findViewById(R.id.time);
title.setText(netdingdata.getTitle());
// 默認值如果為空,不更新
String updateContent = netdingdata.getContent();
if (!TextUtils.isEmpty(updateContent)) {
// modify by qiaopu 用title的view
if (useTitle) {
title.setText(netdingdata.getContent());
content.setText("");
} else {
content.setText(netdingdata.getContent());
}
// end modify
}
description.setText(netdingdata.getDescription());
time.setText(netdingdata.getTime());
}
@Override
public void onViewChanged(int viewIndex) {
if (viewIndex < 0 || viewIndex >= mTotalDingnum) {
// Log.d(TAG, "invalid mCurrentDownUrlIndex");
return;
}
if (mCurrentDownUrlIndex != viewIndex) {
View view = mWorkspace.getChildAt(mCurrentDownUrlIndex);
if (view != null) {
}
mCurrentDownUrlIndex = viewIndex;
mDingLayout.updateDots(mTotalDingnum, mCurrentDownUrlIndex);
}
}
}
public class DingLayout extends RelativeLayout {
// /** Context */
// private Context mContext;
/** MESSAGE_MOVING_UP表示手勢的動作為向上滑. */
public static final int MESSAGE_MOVING_UP = 0;
/** MESSAGE_MOVING_UP表示手勢的動作為向下滑. */
public static final int MESSAGE_MOVING_DOWN = 1;
/** MESSAGE_MOVING_UP表示手勢的動作為點擊. */
public static final int MESSAGE_MOVING_CLICK = 2;
/** isUp為判斷workspace是否在上方. */
private boolean mIsUp = false;
/** isUp為判斷滑動的動畫是否在進行中. */
private boolean mIsMove = false;
/** 可上下滑動的Layout,包括Workspace和點點提示。 */
private ViewGroup mUpDownLayout;
/** Workspace. */
private Workspace mSpace;
/** 點點提示Workspace當前頁的Layout。 */
private LinearLayout mDotsLayout;
/** 點點的Y坐標偏移。由於點點需要顯示在DING圖標下面,而DING圖標只有在Workspace的screen中才有,所以用此全局來計算並記住。 */
private int mDotsOffsetY;
/** 當前索引。 */
private int mCurrent = -1;
/** log tag. */
private static final String TAG = "DingLayout";
/** 動畫運行時間. */
private static final int ANIMATIONTIME = 650;
/** mHandlerFromMainActivity從main activity傳進來. */
private Handler mHandlerFromMainActivity;
/** 是否是動畫進行中.*/
private boolean isRunning = false;
/** Context*/
private Context mContext = null;
/**
* view的構造函數.
*
* @param context
* context
* @param attrs
* attrs
*
*/
public DingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mIsUp = false;
isRunning = false;
mContext = context;
}
/**
* @return 為ding在上還是在底下的標識
*/
public boolean isUp() {
return mIsUp;
}
/**
* 把mainActivity的hander傳入這個view.
* @param handlerFromMainActivity HandlerFromMainActivity
*/
public void setHandlerFormActivity(Handler handlerFromMainActivity) {
this.mHandlerFromMainActivity = handlerFromMainActivity;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//如果在動畫進行中,不進行event的分發
if (isRunning) {
return true;
}
return super.dispatchTouchEvent(ev);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
//下面兩句保證初始化時workspace的位置在上面或是在下面
if (mIsUp) {
layoutUp();
} else {
layoutDown();
}
if (mDotsOffsetY == 0) {
View dingView = findViewById(R.id.ding_view);
if (dingView != null) {
mDotsOffsetY = dingView.getBottom();
System.out.println("=====mDotsOffsetY="+mDotsOffsetY);
}
}
if (mDotsOffsetY > 0) {
//需要修改LayoutParams,否則在parent調用Layout的時候,坐標又會被改變。
LayoutParams params = (LayoutParams) mDotsLayout.getLayoutParams();
params.topMargin += mDotsOffsetY;
mDotsLayout.layout(mDotsLayout.getLeft(),
mDotsLayout.getTop() + mDotsOffsetY,
mDotsLayout.getRight(),
mDotsLayout.getBottom() + mDotsOffsetY);
//只需執行一次。
mDotsOffsetY = -1;
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mUpDownLayout = (ViewGroup) findViewById(R.id.ding_updown_layout);
mSpace = (Workspace) findViewById(R.id.workspace);
mSpace.setHandler(mHandler);
//
mDotsLayout = (LinearLayout) findViewById(R.id.dots_layout);
}
/**
* 更新點點的狀態,包括總數和當前位置。
* @param total 總數。
* @param current 當前位置。
*/
public void updateDots(int total, int current) {
Workspace.updateDots(mDotsLayout, total, current, null);
}
/**
* setCurrentScreen.
* @param index Index.
*/
public void setCurrentScreen(int index) {
mSpace.setCurrentScreen(index);
updateDots(getDingCount(), index);
}
/**
* set IsUp的值.
* @param isUp set mIsUp值
*/
public void setIsUp(boolean isUp) {
this.mIsUp = isUp;
}
/**
* 獲取Ding的數量。
* @return 數量。
*/
private int getDingCount() {
List list = DingManager.getInstance(getContext())
.getDingList();
return list.size();
}
/**
* 向上移的動畫.
*/
private void moveUp() {
logCat("moveUp mToppanel.getWidth()=" + mUpDownLayout.getWidth()
+ "mToppanel.getHeight()=" + mUpDownLayout.getHeight());
layoutUp();
Animation upAnimation = new TranslateAnimation(0, 0,
getWorkSpaceDownPosition(), 0);
upAnimation.setDuration(ANIMATIONTIME);
upAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mIsMove = true;
isRunning = true;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mIsMove = false;
isRunning = false;
if (mHandlerFromMainActivity != null) {
Message msg = mHandlerFromMainActivity.obtainMessage();
msg.what = SearchListener.MSG_ANIMATION_DONE;
mHandlerFromMainActivity.handleMessage(msg);
mHandlerFromMainActivity
.sendEmptyMessage(SearchListener.MSG_DING_UP_FINISHED);
mHandlerFromMainActivity
.sendEmptyMessage(SearchListener.MSG_DING_MOVE_UP);
}
}
});
if (mHandlerFromMainActivity != null) {
Message msg = mHandlerFromMainActivity.obtainMessage();
msg.what = SearchListener.MSG_ANIMATION_PREPARE;
mHandlerFromMainActivity.handleMessage(msg);
}
mUpDownLayout.startAnimation(upAnimation);
}
/**
* 向下移的動畫.
*/
private void moveDown() {
if (mHandlerFromMainActivity != null) {
//
}
logCat("mToppanel.getWidth()=" + mUpDownLayout.getWidth()
+ "mToppanel.getHeight()=" + mUpDownLayout.getHeight());
layoutDown();
Animation downAnimation = new TranslateAnimation(0, 0,
-getWorkSpaceDownPosition(), 0);
downAnimation.setDuration(ANIMATIONTIME);
downAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mIsMove = true;
isRunning = true;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mIsMove = false;
isRunning = false;
if (mHandlerFromMainActivity != null) {
Message msg = mHandlerFromMainActivity.obtainMessage();
msg.what = SearchListener.MSG_ANIMATION_DONE;
mHandlerFromMainActivity.handleMessage(msg);
}
}
});
if (mHandlerFromMainActivity != null) {
Message msg = mHandlerFromMainActivity.obtainMessage();
msg.what = SearchListener.MSG_ANIMATION_PREPARE;
mHandlerFromMainActivity.handleMessage(msg);
}
mUpDownLayout.startAnimation(downAnimation);
}
/**
* 上移。
*/
private void layoutUp() {
mUpDownLayout.layout(mUpDownLayout.getLeft(), 0, mUpDownLayout.getRight(),
mUpDownLayout.getHeight());
mUpDownLayout.setDrawingCacheEnabled(true);
mUpDownLayout.buildDrawingCache();
}
/**
* 下移。
*/
private void layoutDown() {
int workSpacePosition = getWorkSpaceDownPosition();
mUpDownLayout.layout(mUpDownLayout.getLeft(), workSpacePosition,
mUpDownLayout.getRight(), workSpacePosition + mUpDownLayout.getHeight());
mUpDownLayout.setDrawingCacheEnabled(false);
}
/**
* 獲取workspace下移後的(top)position。
* @return position.
*/
private int getWorkSpaceDownPosition() {
//A部分的高度
int heightPartA = getResources().getDimensionPixelSize(R.dimen.browseraddview_height);
return getHeight() - heightPartA;
}
/**
* 打log用.
* @param log log
*/
private void logCat(String log) {
}
/**
* 處理動畫的Handler.
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (mIsMove) {
return;
}
switch (msg.what) {
case MESSAGE_MOVING_UP:
// top.setVisibility(View.GONE);
if (!mIsUp) {
mIsUp = true;
moveUp();
}
break;
case MESSAGE_MOVING_DOWN:
if (mIsUp) {
mIsUp = false;
// if(mHandler_fromActivity != null){
// mHandler_fromActivity.sendEmptyMessage(SearchListener.MSG_DING_MOVE_DOWN);
// }
moveDown();
}
break;
case MESSAGE_MOVING_CLICK:
Object obj = msg.obj;
Float t = (Float) obj;
int dingLayoutHeight = getResources().getDimensionPixelSize(R.dimen.browseraddview_height);
// t
item的布局:
ym——Android仿QQ5.0側滑菜單ResideMenu源碼分析
原創博客地址:點擊傳送 AndroidResideMenu 先看看如何使用: 把項目源碼下載下來導入工程,可以看到 ResideMenu為引用工程,再看
ObjectAnimator詳解(測試用,承接Android動畫操作中的測試)
廢話不多說直接看代碼需要注意的是ObjectAnimator.ofFloat(xiaoming, “age”, 0f,100f)傳入的是float
Android 中自定義控件之判斷還剩多少可輸入字符的EditText
最近做的項目有個需求就是判斷一下還 剩多少字符可輸入,也就是對EditText 的文本變化做監聽 ,功能實現了,但是感覺使用組合方式,每次都要編寫,還不如寫
Java操作Ant壓縮和解壓文件及批量打包Anroid應用
實現zip/tar的壓縮與解壓java中實際是提供了對 zip等壓縮格式的支持,但是為什麼這裡會用到ant呢?原因主要有兩個:1. java提供的類對於包括有