編輯:關於Android編程
ViewPager是android擴展包android.support.v4 裡的一個繼承與ViewGroup組件,通過布局管理器可以實現左右滑動來顯示不同的View。而這個View由PagerAdapter產生,用法類似於ListView和listView的Adapter。
下面是一個簡單例子(布局文件):
PagerTabStrip是ViewPager切換的標題欄,不需要可以不寫。現在示例中暫時寫上看效果。
前面說了像listview一樣,我們還需要一個adapter。ok,那麼我們來看看PagerAdapter怎麼寫。
public class MyPagerAdapter extends PagerAdapter{
private Context context;
private int[] imgid = new int[]{
R.drawable.h_1,
R.drawable.h_2,
R.drawable.h_3,
R.drawable.h_4
};
public MyPagerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return imgid.length;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// 判斷是否由對象產生頁面
return arg0==arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//初始化postiton位置的界面
ImageView imageView = new ImageView(context);
imageView.setImageResource(imgid[position]);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// 生命周期中的資源回收,系統消耗position時會調用
container.removeView((View)object);
Drawable draw = ((ImageView)object).getDrawable();
if(draw!=null){
//解除Drawable 對view 的引用
draw.setCallback(null);
}
}
}
可以看到我們只需要繼承與PagerAdapter並實現和重寫上面幾個必要的方法即可。代碼中有注釋,不一一解釋了。
activity中呢,很簡單,給ViewPager set一下我們的PagerAdapter就行了。
public class MainActivity extends Activity {
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(new MyPagerAdapter(this));
}
}
來看看效果。

這樣滑動切換界面就實現了,裡面的ImageView可以替換成任何View.
大家可以看到PagerTabStrip是一個黑色的條,跟隨滾動,這個可以去掉,也可以定義成我們想要的樣子。
首先我們可以直接在PagerAdapter中設置要顯示的標題,只要再重寫一個PagerAdapter的方法:
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return titls[position];
}
PagerTabStrip的樣式也是可以定義的,下面給出一些常用的方法,根據需要定義。
//設置下劃線的顏色,有兩種方法,使用其中一種即可
pagerTabStrip.setTabIndicatorColor(Color.RED);//拉姆紅
pagerTabStrip.setTabIndicatorColorResource(R.color.blue);//雷姆藍(自定義的color資源)
//設置背景顏色
pagerTabStrip.setBackgroundColor(Color.CYAN);
ps:若出現初始加載時不顯示標簽文字,滑動後卻顯示。可以嘗試換android_support_v4包。(換成實例源碼中的可以,可能是某些版本的v4包有bug)
其實PagerTabStrip並沒什麼卵用,實際項目很少用到,因為它不符合中國的審美觀。我們看到的大多數app的標題欄都是全部顯示出來的。就像這樣。

那麼這效果怎麼實現呢,這就需要自定義標題欄。

我的標題欄應該像這樣的,我們讓左邊的那塊東西隨著當前item不一樣,進行滑動就行了。
布局應該是這樣的。
我們使用了相對布局,對標題使用線性布局,而滑塊使用imageView蓋上上面。這比較簡單,下面就是滑塊的動畫實現了。
/**
* 滑塊動畫
* @param fromIndex 當前標簽
* @param toIndex 目標標簽
*/
public void startAnimation(int fromIndex,int toIndex){
int bitmapWidth = cursor.getWidth();
int tileWidth = tvTile[0].getWidth();
int offset = (tileWidth - bitmapWidth)/2;
Animation animation = new TranslateAnimation(fromIndex*tileWidth+offset, toIndex*tileWidth+offset, 0,0);
animation.setFillAfter(true);
animation.setDuration(200);
cursor.startAnimation(animation);/*
}
上面是動畫的方法,具體計算位置的方法是:1.先計算出滑塊和標簽兩邊的offset.2.移動時就是index*tileWidth+offset 可以計算出目標位置。看圖理解:

動畫完成了,那麼就需要監聽viewPager的itemchange事件了。
如下:
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int pos) {
startAnimation(currentPage, pos);
currentPage = pos;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
主要是實現了onPageSelected(int pos)方法。進行啟動動畫。
還差點什麼嗎?有,就是標題欄點擊時能切換頁面了。這是簡單,給每個標題view添加點擊監聽器即可。
for (int i = 0; i < tvTile.length; i++) {
tvTile[i].setTag(i);
tvTile[i].setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int item = (Integer) v.getTag();
viewPager.setCurrentItem(item);
}
});
}
做到這裡其實還有一個bug,那就是初始狀態沒寫。我發現在oncreate,onresume等獲取控件的大小都是0的。因此初始化時,需要重寫如下方法才能正確獲取大小:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
bitmapWidth = cursor.getWidth();
tileWidth = tvTile[0].getWidth();
offset = (tileWidth - bitmapWidth)/2;
startAnimation(0, 0);
}
自定義的標題導航欄就到此為止了。
實現原理和上面類似,只是相當於將標題換成了小圓點而已,再增加自動輪播。
在res文件夾下新建文件夾drawable.並新建如下文件
白色小圓點(可用圖片代替)
route_point_draw.xml
白色半透明小圓點(可用圖片代替)
route_point_draw_b.xml
小圓點selector
route_point.xml
slide_view.xml
這樣我們的界面就有了。
剩的就是自動輪播了。
pagerAdapter的實現和上面一樣,這部分就不重復了。
ublic class SlideShowView extends FrameLayout implements OnPageChangeListener{
private int SLIDE_PIC_NUM = 4;
private long SLIDE_TIME = 500;
private int[] pic_id;
private List dotViews;
private ViewPager viewPager;
private int currentPager;
private boolean isAutoPlay = false;
private ScheduledExecutorService scheduledExe;
private Handler hander = new Handler(){
public void handleMessage(android.os.Message msg) {
viewPager.setCurrentItem(currentPager);
};
};
/**
* @param context
* @param attrs
* @param defStyleAttr
*/
public SlideShowView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
initview(context);
startPlay();
}
public SlideShowView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SlideShowView(Context context) {
this(context,null);
}
/**
* 4個點
* @param reid
*/
public void setImageIds(int ... reid){
pic_id = reid;
viewPager.invalidate();
}
private void init(){
dotViews = new ArrayList();
pic_id = new int[]{
R.drawable.h_1,
R.drawable.h_2,
R.drawable.h_3,
R.drawable.h_4
};
}
private void initview(Context context){
LayoutInflater.from(context).inflate(R.layout.slide_view,this,true);
for (int i = 0; i < pic_id.length; i++) {
/*ImageView view = new ImageView(context);
view.setImageResource(pic_id[i]);
images.add(view);*/
}
dotViews.add(findViewById(R.id.t_1));
dotViews.add(findViewById(R.id.t_2));
dotViews.add(findViewById(R.id.t_3));
dotViews.add(findViewById(R.id.t_4));
for (View dotview : dotViews) {
dotview.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.t_1:
currentPager = 0;
break;
case R.id.t_2:
currentPager = 1;
break;
case R.id.t_3:
currentPager = 2;
break;
case R.id.t_4:
currentPager = 3;
break;
default:
break;
}
viewPager.setCurrentItem(currentPager);
}
});
}
viewPager = (ViewPager) findViewById(R.id.slipe_pager);
viewPager.setAdapter(new MypagerAdapter());
viewPager.setOnPageChangeListener(this);
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int position) {
currentPager = position;
for (int i = 0; i < dotViews.size(); i++) {
if(position==i){
dotViews.get(i).setSelected(true);
}else{
dotViews.get(i).setSelected(false);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case ViewPager.SCROLL_STATE_DRAGGING://手勢滑動
isAutoPlay = false;
break;
case ViewPager.SCROLL_STATE_SETTLING://界面切換
isAutoPlay = true;
break;
case ViewPager.SCROLL_STATE_IDLE://切換結束
//最後一張右滑動到第一張
if(viewPager.getCurrentItem() == viewPager.getAdapter().getCount()-1 && !isAutoPlay){
viewPager.setCurrentItem(0);
}
if(viewPager.getCurrentItem() == 0 && !isAutoPlay){
viewPager.setCurrentItem(viewPager.getAdapter().getCount()-1);
}
break;
default:
break;
}
}
public void startPlay(){
scheduledExe = Executors.newSingleThreadScheduledExecutor();
scheduledExe.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// 輪播任務
synchronized (SlideShowView.this) {
currentPager = (currentPager+1)%pic_id.length;
hander.obtainMessage().sendToTarget();
}
}
}, 1, 4,TimeUnit.SECONDS);
}
public void stopPlay(){
scheduledExe.shutdown();
}
}
最終效果

這裡的核心是使用了單一線程池循環發送handler信息,讓viewPager循環播放圖片。而小圓點的狀態變化是通過selected狀態實現,對於小圓點selector 的xml文件
這裡的輪播時間,圖片數量,來源都寫死了,要想修改直接將源碼修改即可。還有就是點擊圖片跳轉的功能,只需給每個item加入點擊事件即可,仿照上面自定義標題實現的點擊。
有些軟件滑動方式的有點不同,它的標題滑塊是跟隨著手指滑動而滑動的,就像下圖一樣。

思路:
既然要跟隨頁面滑動而滑動,那麼就需要監聽滑動事件,並計算出相應的距離。頁面滑動一頁,而導航欄的標題滑動一小格。假設是4個標簽卡,那麼就是4:1。
下面來實現一下,大體和上面的標題滑動差不多,我們之間復制進行修改。把動畫部分去掉。
實現方法
/*pos是當前頁面的標號,percent是當前頁面滑動的百分比,px是當前頁面滑動的像素*/
@Override
public void onPageScrolled(int pos, float percent, int px) {
if(scrolling){
float w = pos*tileWidth+offset+percent*tileWidth;//計算滑塊的x坐標
cursor.setX(w);//設置滑塊的x坐標
}
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
switch (state) {
case ViewPager.SCROLL_STATE_DRAGGING://手勢滑動
scrolling = true;
break;
case ViewPager.SCROLL_STATE_SETTLING://界面切換
break;
case ViewPager.SCROLL_STATE_IDLE://切換結束
scrolling = false;
break;
default:
break;
}
}
實現OnPageChangeListener中的onPageScrolled方法即可。
初始化就是cursor.setX(offset);具體查看源碼。
android圖形圖像處理PorterDuffXfermode
設置兩張圖片重疊的模式。在正常的情況下,在已有的圖像上繪圖將會在其上面添加一層新的形狀。如果新的Paint是完全不透明的,那麼它將完全遮擋住下面的Paint;如果它是部分
Android開發之基本控件和四種布局方式詳解
Android中的控件的使用方式和iOS中控件的使用方式基本相同,都是事件驅動。給控件添加事件也有接口回調和委托代理的方式。今天這篇博客就總結一下Android中常用的基
Android中常用的五種數據存儲方式
第一種: 使用SharedPreferences存儲數據適用范圍:保存少量的數據,且這些數據的格式非常簡單:字符串型、基本類型的值。比如應用程序的各種配置信息(如是否打開
新聞網絡版
一、---框架---首先還是來把總體的編碼流程來樹梳理一下,按照這個順序來編碼可以使思路更加清晰。(1)創建兩個View,一個listview一個item_view(2)