main.xml
成都創(chuàng)新互聯(lián)公司是專業(yè)的西安網(wǎng)站建設(shè)公司,西安接單;提供成都網(wǎng)站制作、做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行西安網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
先定義一個(gè)GridView,然后再定義一個(gè)ImageSwitcher
LinearLayout?xmlns:android=""??
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"?
GridView
android:id="@+id/gridView1"
android:layout_height="fill_parent"
android:layout_width="300px"
android:layout_marginTop="6px"
android:horizontalSpacing="3px"
android:verticalSpacing="3px"
android:numColumns="4"/
ImageSwitcher
android:id="@+id/imageSwicher1"
android:padding="20px"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/ImageSwitcher
/LinearLayout
MainActivity代碼如下
public?class?MainActivity?extends?Activity?{
private?int[]?imageId?=?new?int[]?{?R.drawable.w1,?R.drawable.w2,
R.drawable.w3,?R.drawable.w4,?R.drawable.w5,?R.drawable.w6?};
private?ImageSwitcher?imageSwitcher;
@Override
protected?void?onCreate(Bundle?savedInstanceState)?{
//?TODO?Auto-generated?method?stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageSwitcher?=?(ImageSwitcher)?findViewById(R.id.imageSwicher1);
imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));//?設(shè)置淡入動(dòng)畫
imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));//?設(shè)置談出動(dòng)畫
imageSwitcher.setFactory(new?ViewFactory()?{
@Override
public?View?makeView()?{
//?TODO?Auto-generated?method?stub
ImageView?imageView?=?new?ImageView(MainActivity.this);//?實(shí)例化一個(gè)ImageView類的對(duì)象
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);//?設(shè)置保持縱橫比居中縮放圖像
imageView.setLayoutParams(new?ImageSwitcher.LayoutParams(//?主要要是用ImageSwitcher的LayoutParams
LayoutParams.WRAP_CONTENT,?LayoutParams.WRAP_CONTENT));
return?imageView;
}
});
imageSwitcher.setImageResource(imageId[0]);
GridView?gridView?=?(GridView)?findViewById(R.id.gridView1);
BaseAdapter?adapter?=?new?BaseAdapter()?{
/*
*?獲得數(shù)量
*
*?@see?android.widget.Adapter#getCount()
*/
@Override
public?int?getCount()?{
//?TODO?Auto-generated?method?stub
return?imageId.length;
}
@Override
public?Object?getItem(int?position)?{
//?TODO?Auto-generated?method?stub
return?position;
}
/**
*?獲得當(dāng)前選項(xiàng)
*/
@Override
public?long?getItemId(int?position)?{
//?TODO?Auto-generated?method?stub
return?position;
}
@Override
public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{
//?TODO?Auto-generated?method?stub
ImageView?imageView;
if?(convertView?==?null)?{
imageView?=?new?ImageView(MainActivity.this);
/**?設(shè)置圖像的寬度和高度?**/
imageView.setAdjustViewBounds(true);
imageView.setMaxWidth(150);
imageView.setMaxHeight(113);
imageView.setPadding(5,?5,?5,?5);
}?else?{
imageView?=?(ImageView)?convertView;
}
imageView.setImageResource(imageId[position]);
return?imageView;
}
};
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new?OnItemClickListener()?{
@Override
public?void?onItemClick(AdapterView??arg0,?View?arg1,?int?arg2,
long?arg3)?{
//?TODO?Auto-generated?method?stub
imageSwitcher.setImageResource(imageId[arg2]);//?顯示選中的圖片
}
});
}
}
原文博客鏈接
用過 iOS 的都知道,擬物理的回彈效果在上面非常普遍,因?yàn)檫@是 iOS 系統(tǒng)支持的一套 UI 框架,但是 Android 就沒有了,就拿圖片查看器來講,iOS 的效果就是感覺一張圖片被綁定在了彈簧裝置上,滑動(dòng)很自然,Android 沒有自帶的圖片查看器,需要自己實(shí)現(xiàn)
市面上主流的圖片查看器都沒有回彈的效果,一部分原因是沒有這個(gè)需求,還有一部分是實(shí)現(xiàn)麻煩,這里講述一個(gè)個(gè)人認(rèn)為最好的方案
一個(gè)圖片查看器,要求可以滑動(dòng) Fling,觸碰到邊界的時(shí)候回彈,有越界回彈的效果,支持雙指縮放,雙擊縮放
咋一看需求,應(yīng)該好寫,滾動(dòng)的時(shí)候用 Scroller 來解決,回彈效果直接用 ValueAnimator ,設(shè)置插值器為減速插值器來解決??此坪?jiǎn)單,但是因?yàn)槭欠挛锢硇Ч虚g牽扯到從滾動(dòng)到回彈的時(shí)候( Scroller 動(dòng)畫切換到 ValueAnimator 動(dòng)畫)的速度銜接問題,要看上去從滾動(dòng)到開始回彈至結(jié)束沒有突兀,中間的特判邊界處理是很麻煩的,還要牽扯到縮放,所以不考慮這種方案
既然是要模擬現(xiàn)實(shí)中的物理效果,為何不在每一幀根據(jù)當(dāng)前的狀態(tài)得到對(duì)用的加速度,然后去計(jì)算下一幀的狀態(tài)位置,這樣只要模擬現(xiàn)實(shí)中的物理加速度不就可以實(shí)現(xiàn)了嗎,那些邊界特判之類的就可以去見閻王了
方案確定完畢,接下來就是選定加速度的方程,要模擬彈簧的效果,拉力很簡(jiǎn)單,用胡克定律嘛! F = k * dx ,摩擦力呢? Ff = μ*FN ? 這里推薦一個(gè)更加好的方案,借鑒自 Rebound 庫(kù),這是 Facebook 的一個(gè)彈簧動(dòng)畫庫(kù),設(shè)定一個(gè)目的數(shù)值,它會(huì)根據(jù)當(dāng)前的拉力,摩擦力,速度然后變化到目標(biāo)值,加速度方程為
其中 tension 為彈性系數(shù), friction 為摩擦力系數(shù),為什么讓摩擦力和速度成正比呢?如果摩擦力和速度成正比,那么就不存在靜摩擦力,也就是不存在物體靜止情況下拉力小于摩擦力的情況(因?yàn)樗俣葹?的時(shí)候,阻力為0,除非拉力為0),物體肯定會(huì)向目標(biāo)地點(diǎn)靠近,遏制了物體摩擦力過大而無(wú)法達(dá)到目的地情況
為了方便接入各種 View ,設(shè)計(jì)一個(gè) ZoomableGestureHelper 類
設(shè)計(jì)目的,我只需要知道視圖的大小邊界 (bounds) 和內(nèi)部可滾動(dòng)回彈的邊界 (innerBounds),就可以通過計(jì)算得到一個(gè)新的轉(zhuǎn)換矩陣
對(duì)于物理狀態(tài),需要一個(gè)類 SpringPhysicsState 來做存儲(chǔ),里面包含了速度、拉力系數(shù)、摩擦力系數(shù),不保存位置,因?yàn)槲恢檬峭ㄟ^ getBounds 動(dòng)態(tài)計(jì)算得到的
速度分解成水平方向和垂直方向,因?yàn)樘幚矸椒ㄒ粯?,下面只講述垂直方向的計(jì)算
狀態(tài)1 :其中一邊有越界
分析一下上圖中的位置,藍(lán)色部分為內(nèi)部圖片,它被拖動(dòng)越界了,此時(shí)的合力應(yīng)該為 tension * dx - friction * v , v 為圖片在 y 軸方向上的速度,( dx 和 v 都是矢量,我暫且設(shè)置向右和向下為正),之后就直接調(diào)用 invalidate(); ,就可以播放動(dòng)畫了。
狀態(tài)2:兩邊都沒越界
此時(shí)因?yàn)閮蛇叾紱]有越界,所以應(yīng)該不存在拉力,可以認(rèn)為此時(shí) dx 為0,摩擦力需要注意下,因?yàn)榭梢灾С只瑒?dòng)( Fling ),所以此時(shí)的摩擦力要比之前越界回彈時(shí)候的摩擦力小,至于具體數(shù)值,文末會(huì)給出
狀態(tài)3:兩邊都超出
此時(shí)兩邊都超出邊界,藍(lán)色區(qū)域應(yīng)該和紅色區(qū)域中心綁定,所以此時(shí)的 dx 為 dxBottom - dxTop (注意符號(hào),因?yàn)?dx 為矢量,所以不能是 dxTop - dxBottom )
縮放的方法和移動(dòng)一致,設(shè)定 tension 和 friction ,邊界設(shè)定為外面紅色的框框,藍(lán)色區(qū)域無(wú)法某一邊充滿紅色區(qū)域的時(shí)候,有拉力,否則沒拉力,摩擦力一直存在,至于雙擊放大和放小,只需要在雙擊的時(shí)候給縮放狀態(tài)設(shè)置一個(gè)初速度,然后 invalidate(); ,搞定!是不是很簡(jiǎn)單啊
時(shí)間這一個(gè)參數(shù)在計(jì)算中是非常重要的,這關(guān)系到當(dāng)前微分狀態(tài)的數(shù)值變化,假如用歐拉方法模擬速度和位置的變化, x' = x + v * dt , v' = v + a * dt ,公式可以看出時(shí)間決定了動(dòng)畫的快慢,為了接近現(xiàn)實(shí)物理時(shí)間,這里采用的時(shí)間單位為秒(計(jì)算機(jī)中常用的是毫秒)
確定了單位,還需要控制一下時(shí)間間隔的數(shù)值范圍,我們不能讓兩次 computeScroll 的時(shí)間間隔過于短或者過于長(zhǎng),這里采用的策略為固定每次計(jì)算時(shí)候的時(shí)間間隔,如果兩次 computeScroll 的時(shí)間間隔小于此時(shí)間間隔,那么保存累計(jì)時(shí)間間隔,等待下一次 computeScroll ,直到大于等于固定的時(shí)間間隔,再用 while 循環(huán)一步一步的計(jì)算
結(jié)束判定是唯一的一個(gè)坑,因?yàn)橛?jì)算機(jī)只是在 dt 時(shí)間內(nèi)模擬速度和位移的變化,不是通過微積分計(jì)算的,存在誤差,比如歐拉方法 x' = x + v * dt 和 v' = v + a * dt 計(jì)算得到的 x' 和 v' 都是近似數(shù)值,把 dt 這段時(shí)間內(nèi)的變化看成了勻變速運(yùn)動(dòng)
所以結(jié)束判定還需要設(shè)置一個(gè)閾值,當(dāng)速度和偏移量小于此數(shù)值的時(shí)候,可以認(rèn)定為達(dá)到了目的地
對(duì)于 ViewPager 的適配有些問題,如果在 Down 的時(shí)候 requestDisallow true 移動(dòng)過程中到了左右邊界又 requestDisallow false ,此時(shí) ViewPager 會(huì)有一個(gè)突變( 突變可恥但有用 ),而且多指頭的時(shí)候可能會(huì)崩潰,這是 ViewPager 的 Bug,具體細(xì)節(jié)請(qǐng)看源碼
android 是linux內(nèi)核,在文件系統(tǒng)中以.開頭的文件或者文件夾都是隱藏文件,因此你可以這樣隱藏:
只需要將這個(gè)目錄的名稱改成.開頭 即可隱藏掉。
圖庫(kù)默認(rèn)有這個(gè)功能,只要你長(zhǎng)按就會(huì)彈出選項(xiàng),選擇隱藏即可
查看隱藏的相冊(cè),在選項(xiàng)選擇顯示隱藏的相冊(cè)即可