編輯:關於Android編程
最近做項目真是頭疼呢?之前想用ListViewAnnotation來著,就是可以實現類似於android 通知欄滑動刪除的效果。好像是一位大牛自己一個人寫的吧。我在這裡首先向他致敬。不過,話說回來,實現原理也是比較易於理解的,就是檢測你的滑動距離以及速度,再作出判斷,進行操作。具體大家參考下Google keep的兩種列表模式下滑動刪除的操作就理解類。
非常不幸的事,我再布局中用了fragment和biewpager,所以產生了手勢沖突,我為此改寫了library裡的手勢操作檢測方法,最後勉強改出來的。但是!!!!效果實在慘不忍睹,只好作罷,最後,思來想去,我決定使用listview item點擊展開來實現我想要的效果。
好吧,廢話說了很多,終於要進入正題了。
首先補充三點知識:
第一點:
getLayoutParams()方法和setLayoutParams()用法
首先,我們利用getLayoutParams()來獲得指定控件的LayoutParams。例如:
LinearLayout.LayoutParams lp = (RelativeLayout.LayoutParams) deletButton.getLayoutParams();
然後,我們可以為deleteButton設置layoutparams屬性,例如:
lp.width = btnWidth;
lp.leftMargin = 10;
最後,我們將設置好的layoutparams屬性設置給指定的控件: deletButton.setLayoutParams(lp);
第二點:
public final int getMeasuredHeight ()
Added in API level 1
Like getMeasuredHeightAndState(), but only returns the raw width component (that is the result is masked by MEASURED_SIZE_MASK).
Returns
The raw measured height of this view.
public final int getHeight ()
Added in API level 1
Return the height of your view.
Returns
The height of your view, in pixels.
getMeasuredHeight()返回的是原始測量高度,與屏幕無關,getHeight()返回的是在屏幕上顯示的高度。實際上在當屏幕可以包裹內容的時候,他們的值是相等的,只有當view超出屏幕後,才能看出他們的區別。當超出屏幕後,getMeasuredHeight()等於getHeight()加上屏幕之外沒有顯示的高度。
第三點:
MeasureSpec的使用。MeasureSpec一般出現在自定義View中,因為在自定義 view中我們經常需要重寫該方法,由它來指定自定義控件在屏幕上的大小。
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
onMeasure傳入的兩個參數是由上一層控件傳入的大小,有多種情況,重寫該方法時需要對計算控件的實際大小,然後調用setMeasuredDimension(int, int)設置實際大小。
onMeasure傳入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸數值,而是將模式和尺寸組合在一起的數值。我們需要通過int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
mode共有三種情況,取值分別為MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
MeasureSpec.EXACTLY是精確尺寸,當我們將控件的layout_width或layout_height指定為具體數值時如andorid:layout_width="50dip",或者為FILL_PARENT是,都是控件大小已經確定的情況,都是精確尺寸。
MeasureSpec.AT_MOST是最大尺寸,當控件的layout_width或layout_height指定為WRAP_CONTENT時,控件大小一般隨著控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時的mode是AT_MOST,size給出了父控件允許的最大尺寸。
MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式。
然後,我們可以調用MeasureSpec.makeMeasureSpec(int size, int mode)來進行設置。
好,現在先上一張demo截圖,使用者可以自己進行擴充。
哈哈,效果還行吧。那個,圖標略顯呆萌,還請不要見笑(自己繪制的,苦逼程序員一只啊)。
好,接下來,我們來看一下動效的實現。當然,先上源碼。
package wenyue.expandlistview.me;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout.LayoutParams;
/**
* animation
* 2014年十一月十八日
* 蒼狼問月
* canglangwenyue.github.io
* @author canglangwenyue
*
*/
public class ViewExpandAnimation extends Animation {
private View mAnimationView = null;
private LayoutParams mViewLayoutParams = null;
private int mStart = 0;
private int mEnd = 0;
public ViewExpandAnimation(View view){
animationSettings(view, 500);
}
public ViewExpandAnimation(View view, int duration){
animationSettings(view, duration);
}
private void animationSettings(View view, int duration){
setDuration(duration);
mAnimationView = view;
mViewLayoutParams = (LayoutParams) view.getLayoutParams();
mStart = mViewLayoutParams.bottomMargin;
mEnd = (mStart == 0 ? (0 - view.getHeight()) : 0);
view.setVisibility(View.VISIBLE);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if(interpolatedTime < 1.0f){
mViewLayoutParams.bottomMargin = mStart + (int) ((mEnd - mStart) * interpolatedTime);
// invalidate
mAnimationView.requestLayout();
}else{
mViewLayoutParams.bottomMargin = mEnd;
mAnimationView.requestLayout();
if(mEnd != 0){
mAnimationView.setVisibility(View.GONE);
}
}
Log.i("hehe", "interpolatedTime = " + interpolatedTime + " , bottomMargin" +
mViewLayoutParams.bottomMargin);
}
}
動效實現的代碼不多,setDuration(duration)設置動效的持續時間。之後調用RelitaveLayout.bottomMargin;對於該屬性developer文檔解釋為The bottom margin in pixels of the child.
mAnimationView.requestLayout();該方法內部會調用Object.layout(...)方法,來重會布局。
至於,listview adapter的重寫,就比較簡單了。所以,不再貼出全部源碼。只說一下需要注意的地方。
首先,你需要在getView(…)中加載自定義listview 的item布局文件:
convertView = myInflater.inflate(R.layout.expand_item, null);
接下來,貼出相應布局文件代碼:
我設置的是默認在activity onStart時嵌套布局中的第二個RelativeLayout布局文件的內容是被隱藏的。
在BaseAdapter中的設置如下:
RelativeLayout footer = (RelativeLayout) convertView
.findViewById(R.id.footer);
int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (mLcdWidth - 10 * mDensity), MeasureSpec.EXACTLY);
footer.measure(widthSpec, 0);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) footer
.getLayoutParams();
params.bottomMargin = -footer.getMeasuredHeight();
footer.setVisibility(View.GONE);
然後,是在onCreate方法中設置setOnItemClickListener方法,在其中設置點擊item後,開始動效,再次點擊則隱藏,且同一時間只有一個item可以展開(因為個人認為用戶不可能在同一時間操作兩個 item的隱藏操作),代碼如下:
if (mLastTouchTag != null) {
View temp = arg0.findViewWithTag(mLastTouchTag);
if (temp != null) {
View footTemp = temp.findViewById(R.id.footer);
if (footTemp != null
&& (footTemp.getVisibility() != View.GONE)) {
footTemp.startAnimation(new ViewExpandAnimation(
footTemp));
}
}
}
mLastTouchTag = (ViewHolder) v.getTag();
// onion555 end
View footer = v.findViewById(R.id.footer);
footer.startAnimation(new ViewExpandAnimation(footer));
好吧,就寫到這裡吧,有什麼問題,請留言。同樣,在最後附上源碼下載地址。
點擊打開鏈接
方法一:Android的界面布局可以用兩種方法,一種是在xml中布局,一種是和JAVA中Swing一樣在JAVA代碼中實現Ui界面的布局,用xml的布局管理器布局是很方便
Android Studio 大家應該都很熟悉了,但是可能很多人都僅限基本的功能使用,而 Android Studio 非常強大,有很多非常實用卻又鮮為人知的小技巧,熟練
開發項目過程中基本都會用到listView的下拉刷新和上滑加載更多,之前大家最常用的應該是pull to refresh或它的變種版吧,google官方在最新的andro
背景先看效果圖:(以公司附近的國貿為中心點)上面是地圖,下面是地理位置列表,有的只有地理位置列表(QQ動態的位置),這是個很常見的功能。它有個專門的叫法:POI周邊搜索。