編輯:關於Android編程
一.前面講了,MainFragment的布局就是一個ViewPager,而ViewPager的一個個頁面就是首頁,日常心理學,用戶推薦日報,電影日報,不許無聊,設計日報,大公司日報,財經日報,互聯網安全,開始游戲,音樂日報,動漫日報,體育日報這13個頁面組成。
所以呢,接下來我們要創建這13個頁面,大致思路就是將這13個頁面共同的內容和邏輯抽取為BasePage,然後13個頁面繼承這個BasePage,在各自的Page裡面寫各自不同的東西。
那BasePage裡面的結構依然是MVC結構,initView()方法裡面是加載布局,initData()方法裡面是加載數據,initListener()方法裡面是加載各種事件。其中我們會為這13個頁面寫一個共同的布局文件,然後在initView()裡面加載出來。這個時候這個布局應該設為成員變量,然後用getRoot()方法得到這個布局。要這個布局有什麼用呢?我們前面說這13個頁面是ViewPager的頁面,在ViewPager的instantiateItem()方法裡面需要加載13個頁面的View。
二.
1.說了這麼多,首先我們要看看13個頁面究竟是什麼樣的。
注意:這13個頁面布局除了首頁不一樣,其他12個頁面都是一樣的,就像上面設計日報的布局一樣。接下來我們用代碼來講到底實現的
2.
代碼:(main_fragment_base_page.xml)
效果:
整個就是一個LinearLayout,上面是一個自己定義的ActionBar,就是一個RelativeLayout,裡面有兩個ImageButton,一個TextView。左邊的ImageButton是開關toggle,右邊的ImageButton是設置setting。這個setting的ImageButton只有首頁有,其他頁面都沒有,所以設為看不見,home頁面的時候再設為看得見。下面就是一個ListView。
這時候你會好奇,中間的東西呢,我特意用半透明的黑色遮住了。這部分布局為什麼不直接放在ListView的上面呢?如果真的把這部分布局放在ListView上面,那麼你的手指往上滑的時候,只有ListView的內容是往上面滾動的,這部分布局是不動的,因為它不是ListView的一部分,怎麼會跟著ListView一起滾呢。所以我們把部分抽取出來,單獨放在一個布局文件,再在代碼中把布局加載成一個View,作為ListView的頭,用ListView的addHeaderView()方法將頭布局加載進來。
3.ListView的頭布局文件 (main_content_head_view.xml)
<framelayout android:layout_height="match_parent" android:layout_width="match_parent"> <framelayout android:layout_height="40dp" android:layout_marginbottom="10dp" android:layout_margintop="20dp" android:layout_width="match_parent"></framelayout> <framelayout android:id="@+id/fl_main_content_lunbo_points" android:layout_alignparentbottom="true" android:layout_centerhorizontal="true" android:layout_height="wrap_content" android:layout_marginbottom="20dp" android:layout_width="wrap_content"> </framelayout> </framelayout>
效果:
整個就是一個LinearLayout,上面是一個RelativeLayout,用黃色框起來的部分在首頁是ViewPager,在其他頁面是ImageView,大小都是一樣,都是match父布局RelativeLayout。現在我們的需求就是ViewPager和ImageView位於相同的位置,只是在不同的頁面一個顯示一個不顯示。怎樣實現呢?很簡單,只要將這兩個布局都放在FrameLayout裡面就可以FrameLayout會把他們疊放在一起,這個時候呢,只要在首頁顯示ViewPager,隱藏ImageView,在其他頁面顯示ImageView,隱藏ViewPager就可以了
藍色框起來的部分也是這樣,TextView和LinearLayout都放在FrameLayout裡面,在首頁顯示TextView,隱藏LinearLayout,在其他頁面顯示LinearLayout,隱藏TextView。
首頁的ViewPager的下面部分會生成和ViewPager的頁面數量相同的灰色的點,當滑倒相應的頁面的時候,相應位置的點會動態變成白色。說起來好像不好理解,其實大部分人在實際使用App的時候應該或多或少地遇到過,聯系下實際就可以了。
4.還有一個地方需要特別講解一下首頁的ViewPager又不是正常的ViewPager,而是一個自定義的InterceptViewPage。我們要繼承一下ViewPager,對它進行一點修改。
代碼:
public class InterceptViewPager extends ViewPager { private float mDownX; private float mDownY; public InterceptViewPager(Context context, AttributeSet attrs){ super(context, attrs); // TODO自動生成的構造函數存根 } public InterceptViewPager(Context context) { super(context); // TODO自動生成的構造函數存根 } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = ev.getX(); mDownY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float moveX = ev.getX(); float moveY = ev.getY(); float dX = moveX - mDownX; float dY = moveY - mDownY; // 如果是橫向滑動 if (Math.abs(dX) > Math.abs(dY)) { // 請求父控件不攔截Touch事件,自己來處理 getParent().requestDisallowInterceptTouchEvent(true); } break; default: break; } return super.dispatchTouchEvent(ev); } }
其實代碼很簡單,就是當橫向滑動的時候,滑動事件讓父組件不要攔截,由自己來處理。如果不做這樣一個小修改的話,你會發現從左往右滑的時候沒有問題,一旦從右往左滑的時候會把菜單區域滑出來,因為父組件也有滑動事件。
三.我們布局都准備好了,現在要回到BasePage頁面把它們加載進來 (BasePage.java)
public abstract class BasePage { // 權限為protected,則所有的子類可以直接使用 protected ImageButton ibLogin; protected ImageButton ibSetting; protected ImageButton ibToggleButton; protected TextView tvTitle; protected ListView lvNews; protected ViewPager vpLunboPic; protected LinearLayout llLunboPoints; protected TextView tvLunboTitle; protected MainActivity mainActivity; protected TextView tvHomeTitle; protected LinearLayout llEditorPics; protected LinearLayout llEditors; private View mBaseView; protected FrameLayout mFlLunboPoints; protected ImageView ivPic; public BasePage(MainActivity mainActivity) { // 把上下文傳進來,即MainActivity,MainActivity是Activity,也是Context的子類 this.mainActivity = mainActivity; // 加載布局 initView(); // 初始化事件 initListener(); } /** * 初始化事件 */ protected void initListener() { // 開關一點擊,則拿到SlidingMenu,用toggle方法控制菜單區域的開關 ibToggleButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mainActivity.getSlidingMenu().toggle(); } }); // 設置按鈕一點擊,則進入設置的Activity ibSetting.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(mainActivity,SettingActivity.class); mainActivity.startActivity(intent); } }); } /** * * @param themeDailyNumber主題日報的序號 * MainFragment中的ViewPager的instantiateItem方法中調用該方法為布局加載數據 */ public void initData(String themeDailyNumber){ }; protected void initView() { // 加載布局 mBaseView = View.inflate(mainActivity, R.layout.main_fragment_base_page, null); ibSetting = (ImageButton) mBaseView.findViewById(R.id.ib_base_setting); tvTitle = (TextView) mBaseView.findViewById(R.id.tv_base_title); lvNews = (ListView) mBaseView.findViewById(R.id.lv_main_content_news); ibToggleButton = (ImageButton) mBaseView .findViewById(R.id.ib_base_toggle); /* vpLunboPic= (ViewPager) mBaseView .findViewById(R.id.vp_main_content_luobopic); llLunboPoints = (LinearLayout) mBaseView .findViewById(R.id.ll_main_content_lunbo_points); tvLunboTitle = (TextView) mBaseView .findViewById(R.id.tv_main_content_news_title); tvHomeTitle = (TextView) mBaseView .findViewById(R.id.tv_main_content_home_title); llEditorPics = (LinearLayout) mBaseView .findViewById(R.id.ll_main_content_editor_pics); llEditors = (LinearLayout) mBaseView .findViewById(R.id.ll_main_content_editors);*/ // 為ListView加載頭布局 initHeadView(); } private void initHeadView() { // 加載頭布局,並拿出裡面的組件 View headView = View.inflate(mainActivity, R.layout.main_content_head_view, null); vpLunboPic = (ViewPager) headView .findViewById(R.id.vp_main_content_luobopic); ivPic = (ImageView) headView.findViewById(R.id.iv_main_content_pic); llLunboPoints = (LinearLayout) headView .findViewById(R.id.ll_main_content_lunbo_points); tvLunboTitle = (TextView) headView .findViewById(R.id.tv_main_content_news_title); tvHomeTitle = (TextView) headView .findViewById(R.id.tv_main_content_home_title); llEditorPics = (LinearLayout) headView .findViewById(R.id.ll_main_content_editor_pics); llEditors = (LinearLayout) headView .findViewById(R.id.ll_main_content_editors); mFlLunboPoints = (FrameLayout) headView.findViewById(R.id.fl_main_content_lunbo_points); // 把頭布局加進ListView中 lvNews.addHeaderView(headView); } /** * @return布局View,MainFragment中的ViewPager的instantiateItem調用這個方法, * 可以把頁面的布局顯示在ViewPager上面 */ public View getRoot() { return mBaseView; } }
四. 創建首頁,日常心理學,用戶推薦日報,電影日報,不許無聊,設計日報,大公司日報,財經日報,互聯網安全,開始游戲,音樂日報,動漫日報,體育日報這13個頁面。
所有頁面都繼承BasePage,並重寫initData()方法,super.initData(themeDailyNumber)執行父類的initData()方法中的所有邏輯,然後再執行自己的方法
以設計日報DesignPage為例:
public class DesignPage extends ThemeDailyBasePage { public DesignPage(MainActivity mainActivity) { super(mainActivity); // TODO自動生成的構造函數存根 } @Override public void initData(String themeDailyNumber) { tvTitle.setText("設計日報"); super.initData(themeDailyNumber); } }
其他的頁面都是這樣,頁面就加載好了,怎樣為各個頁面加載數據後面會講。
五.13個頁面終於創建好了,現在我們要把他們作為數據源添加到ViewPager裡面去
public class MainFragment extends BaseFragment { // 13個頁面的集合 private ListallPages = new ArrayList (); private MyViewPager mViewPager; // 12個主題日報的id,例如日常心理學的id為13,用戶推薦日報對應的id為12, // 後面獲取相應的主題日報的url為http://news-at.zhihu.com/api/4/theme/ + id // 例如要拿到日常心理學日報的數據url為http://news-at.zhihu.com/api/4/theme/13 private String[] themeDailyNumber = { "13", "12", "3", "11", "4", "5", "6", "10", "2", "7", "9", "8" }; private int selectedPosition = 0; @Override protected View initView() { // 加載布局 View root = View.inflate(mainActivity, R.layout.main_fragment_base, null); // 拿到布局中的ViewPager組件 mViewPager = (MyViewPager) root.findViewById(R.id.vp_base_fragment); return root; } @Override protected void initData() { super.initData(); // 創建13個頁面對象,作為ViewPager的數據源 HomeBasePage homeBasePage = new HomeBasePage(mainActivity); DailyPsychologyPage dailyPsychologyPage = newDailyPsychologyPage(mainActivity); UserRecommendPage userRecommendPage = new UserRecommendPage(mainActivity); MoviePage moviePage = new MoviePage(mainActivity); NoBoringPage noBoringPage = new NoBoringPage(mainActivity); DesignPage designPage = new DesignPage(mainActivity); BigCompanyPage bigCompanyPage = new BigCompanyPage(mainActivity); FinancePage financePage = new FinancePage(mainActivity); InternetPage internetPage = new InternetPage(mainActivity); GamePage gamePage = new GamePage(mainActivity); MusicPage musicPage = new MusicPage(mainActivity); CartoonPage cartoonPage = new CartoonPage(mainActivity); SportsPage sportsPage = new SportsPage(mainActivity); // 13個頁面加進集合 allPages.add(homeBasePage); allPages.add(dailyPsychologyPage); allPages.add(userRecommendPage); allPages.add(moviePage); allPages.add(noBoringPage); allPages.add(designPage); allPages.add(bigCompanyPage); allPages.add(financePage); allPages.add(internetPage); allPages.add(gamePage); allPages.add(musicPage); allPages.add(cartoonPage); allPages.add(sportsPage); // 為ViewPager設置Adapter MyAdapter myAdapter = new MyAdapter(); mViewPager.setAdapter(myAdapter); } // 根據傳進來的位置編號在13個頁面之間切換 public void switchPage(int position){ // selectedPosition成員變量記錄傳進來的編號 this.selectedPosition = position; // 這個方法會調用Adapter中的getView方法 mViewPager.setCurrentItem(position); } private class MyAdapter extends PagerAdapter{ @Override public int getCount() { // TODO自動生成的方法存根 return allPages.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO自動生成的方法存根 return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Objectobject) { // TODO自動生成的方法存根 container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { // 根據position拿到相應的頁面 BasePage selectedPage = allPages.get(position); // 拿到相應頁面的View,加到容器中 container.addView(selectedPage.getRoot()); // 在這裡調用initData()方法加載13個頁面的數據。 // 如果selectedPosition為0,則為首頁 // 如果selectedPosition不為0,則是其他12個主題日報,把對應的id傳進去 if (selectedPosition != 0) { selectedPage.initData(themeDailyNumber[selectedPosition -1]); }else { selectedPage.initData(""); } return selectedPage.getRoot(); } } }
上面的過程也容易:
1)創建13頁面的對象,加進集合中作為ViewPager的數據源
2)用數據源為ViewPager創建Adapter
3)為ViewPager設置Adapter
你們只需要看懂上面過程的代碼就可以了,其他的後面會講到
0x00原理部分我不獻丑了,上面3篇文章說的很清楚,我直接實戰,講述從0開始如何最終實現加固的整個過程,踩了不少坑。0x01第一步創建被加固Apk,就是你的源碼Apk。
雖然索尼手機賣的不怎麼樣,但是有些東西還是做的挺好的,工業設計就不用說了,索尼的相冊的雙指任意縮放功能也是尤其炫酷。其桌面小部件滾動相冊我覺得也挺好的,比谷歌原生的相冊牆
1.Animation 動畫類型Android的animation由四種類型組成:XML中 alph 漸變透明度動畫效果 scale 漸變尺寸伸縮動畫效果 tr
一、先給大家展示下最終效果 通過以上可以看到,圖一是簡單的使用,圖二、圖三中為結合ViewPager共同使用,而且都可以隨ViewPager的滑動漸變色,不同點是圖二為