編輯:關於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 ListdotViews; 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);具體查看源碼。
設置兩張圖片重疊的模式。在正常的情況下,在已有的圖像上繪圖將會在其上面添加一層新的形狀。如果新的Paint是完全不透明的,那麼它將完全遮擋住下面的Paint;如果它是部分
Android中的控件的使用方式和iOS中控件的使用方式基本相同,都是事件驅動。給控件添加事件也有接口回調和委托代理的方式。今天這篇博客就總結一下Android中常用的基
第一種: 使用SharedPreferences存儲數據適用范圍:保存少量的數據,且這些數據的格式非常簡單:字符串型、基本類型的值。比如應用程序的各種配置信息(如是否打開
一、---框架---首先還是來把總體的編碼流程來樹梳理一下,按照這個順序來編碼可以使思路更加清晰。(1)創建兩個View,一個listview一個item_view(2)