手把手教你實現慕課網導航效果(二)——編碼實現
前言
經過上一篇對慕課網導航效果的分析和驗證,今天我們就來編碼實現這一效果。還沒有看過上一篇文章的同學,建議先看看手把手教你實現慕課網引導頁效果(一)——分析驗證。
通過本篇文章,我們可以學習到:
- 1.ViewPager+Fragment+FragmentPagerAdapter實現滑動導航頁面
- 2.VideoView(播放視頻)的基本使用
- 3.Activity轉間動畫
在編碼之前,先回顧下慕課網的導航效果。

正文
1.首先,我們先實現顯示Logo的Activity(簡稱MainActivity),這個比較簡單。看上面的GIF圖,MainActivity顯示一會時間后向左滑動消失,GuideActivity從右邊滑動出來。那就講講其中的Activity轉間動畫(Transition animation)。
一般使用下面的方式來實現:
public void overridePendingTransition (int enterAnim, int exitAnim)
//通常我們一般在startActivity(Intent)或finish()方法中調用此方法
//其中enterAnim表示新Activity的進入動畫,exitAnim表示舊Activity的退出動畫
//從Android4.1后,可以通過ActivityOptions將轉間動畫作為Bundle傳入startActivity(Activity,Bundle)來實現
來看代碼實現:
public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler();
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
//使用handler定時跳轉到GuideActivity
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(mContext,GuideActivity.class);
//設置跳轉動畫
//第一種方式實現
startActivity(new Intent(mContext,GuideActivity.class));
finish();
overridePendingTransition(R.anim.slide_in_right,R.anim.slide_out_left);
//第二種方式實現
// ActivityOptionsCompat optionsCompat =
// ActivityOptionsCompat.makeCustomAnimation(mContext,R.anim.slide_in_right,
// R.anim.slide_out_left);
// ActivityCompat.startActivity(MainActivity.this,intent,optionsCompat.toBundle());
// startActivity(new Intent(mContext,GuideActivity.class));
// finish();
}
}, 500);
}
}
運行效果:

2.接下來,實現滑動導航效果。相信現在講這個的文章非常多,今天就當再復習一遍。呵呵,溫故而知新。
我們使用ViewPager+Fragment+FragmentPagerAdapter來實現。
一般有三個步驟:
- 1.實現Fragment的子類
- 2.實現FragmentPagerAdapter適配器類
- 3.將第2步生成的Adapter設置為ViewPager的適配器,並使用addOnPageChangeListener方法對ViewPager的Page更改的事件進行監聽來實現標識第幾頁的功能。
在這里,我們只需要創建一種Fragment即可。通過index參數來設置顯示不同的圖片和播放不同的視頻。
下面是GuideFragment的代碼:
/**
* Created by JohnTsai on 16/3/3.
*/
public class GuideFragment extends Fragment {
public static String TAG = GuideFragment.class.getSimpleName();
public static String KEY = "index";
private VideoView mVideoView;
private ImageView mImageView;
private int index;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View guideView = inflater.inflate(R.layout.fragment_guide,container,false);
mVideoView = (VideoView) guideView.findViewById(R.id.videoView);
mImageView = (ImageView) guideView.findViewById(R.id.wordView);
switch (index){
case 0:
mImageView.setImageResource(R.mipmap.guide_1);
break;
case 1:
mImageView.setImageResource(R.mipmap.guide_2);
break;
case 2:
mImageView.setImageResource(R.mipmap.guide_3);
break;
}
Log.d(TAG,"onCreateView");
return guideView;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
index = bundle.getInt(KEY);
Log.d(TAG,"onCreate");
}
public static GuideFragment newInstance(int index) {
Bundle args = new Bundle();
args.putInt(KEY, index);
GuideFragment fragment = new GuideFragment();
fragment.setArguments(args);
return fragment;
}
}
以及GuideActivity的代碼
/**
* Created by JohnTsai on 16/3/3.
*/
public class GuideActivity extends AppCompatActivity{
private ImageView mDotOne,mDotTwo,mDotThree;
private LinearLayout mLayoutBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_guide);
//初始化控件
ViewPager mViewPager = (ViewPager) findViewById(R.id.viewPager);
mDotOne = (ImageView) findViewById(R.id.guide_dot1);
mDotTwo = (ImageView) findViewById(R.id.guide_dot2);
mDotThree = (ImageView) findViewById(R.id.guide_dot3);
mLayoutBtn = (LinearLayout) findViewById(R.id.btn_layout);
GuideFragment guideFragment1 = GuideFragment.newInstance(0);
GuideFragment guideFragment2 = GuideFragment.newInstance(1);
GuideFragment guideFragment3 = GuideFragment.newInstance(2);
List<? extends Fragment> mFragmentList = Arrays.asList(guideFragment1, guideFragment2, guideFragment3);
GuideFragmentPagerAdapter mAdapter = new GuideFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList);
mViewPager.setAdapter(mAdapter);
//設置小圓點
mDotOne.setImageResource(R.mipmap.guide_dot_checked);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mDotOne.setImageResource(R.mipmap.guide_dot_normal);
mDotTwo.setImageResource(R.mipmap.guide_dot_normal);
mDotThree.setImageResource(R.mipmap.guide_dot_normal);
switch (position) {
case 0:
mDotOne.setImageResource(R.mipmap.guide_dot_checked);
break;
case 1:
mDotTwo.setImageResource(R.mipmap.guide_dot_checked);
break;
case 2:
mDotThree.setImageResource(R.mipmap.guide_dot_checked);
break;
}
//設置當滑動到最后一頁時,顯示兩個按鈕
mLayoutBtn.setVisibility(position==2? View.VISIBLE:View.GONE);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
public static class GuideFragmentPagerAdapter extends FragmentPagerAdapter{
private List <? extends Fragment> fragments;
public GuideFragmentPagerAdapter(FragmentManager fm,List<? extends Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
- 最后我們學習VideoView的基本使用。
參考資料:

VideoView繼承自SurfaceView,並實現了MediaPlayerControl接口。用於播放視頻文件。
幾個主要的方法:
- void setVideoPath(String path):以文件路徑的方式設置VideoView播放的視頻源。
- void setVideoURI(Uri uri):以Uri的方式設置VideoView播放的視頻源,可以是網絡Uri或本地Uri。
- void start():開始播放。
- void stopPlayback():停止播放。
- setMediaController(MediaController controller):設置MediaController控制器。
- setOnCompletionListener(MediaPlayer.onCompletionListener l):監聽播放完成的事件。
- setOnErrorListener(MediaPlayer.OnErrorListener l):監聽播放發生錯誤時候的事件。
- setOnPreparedListener(MediaPlayer.OnPreparedListener l)::監聽視頻裝載完成的事件。
下面繼續我們的慕課網視頻引導效果的編碼:
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View guideView = inflater.inflate(R.layout.fragment_guide, container, false);
mVideoView = (VideoView) guideView.findViewById(R.id.videoView);
//獲取放置在raw文件夾得視頻的Uri
Uri uri1 =Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.guide_1);
Uri uri2 =Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.guide_2);
Uri uri3 =Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.guide_3);
Log.d(TAG,"1:"+uri1
+"\n2:"+uri2
+"\n3:"+uri3);
mImageView = (ImageView) guideView.findViewById(R.id.wordView);
switch (index){
case 0:
mImageView.setImageResource(R.mipmap.guide_1);
mVideoView.setVideoURI(uri1);
break;
case 1:
mImageView.setImageResource(R.mipmap.guide_2);
mVideoView.setVideoURI(uri2);
break;
case 2:
mImageView.setImageResource(R.mipmap.guide_3);
mVideoView.setVideoURI(uri3);
break;
}
mVideoView.start();
//對VideoView的完成播放事件進行監聽,完成后再次播放以達到循環播放的效果
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mVideoView.start();
}
});
Log.d(TAG,"onCreateView");
return guideView;
}
運行效果:

看運行效果,發現一個問題,視頻的比例和手機的比例不一致導致右邊出現藍色長條。
這里我們繼承VideoView來自定義設置它的寬和高來解決這個問題:
代碼如下:
/**
* Created by JohnTsai on 16/3/3.
*/
public class CustomWidthHeightVideoView extends VideoView{
private int mWidth = 0;
private int mHeight = 0;
public CustomWidthHeightVideoView(Context context) {
super(context);
}
public CustomWidthHeightVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomWidthHeightVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setWidthHeight(int width,int height){
mWidth = width;
mHeight = height;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(mWidth>0&&mHeight>0)
setMeasuredDimension(mWidth,mHeight);
else
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
}
在onMeasure方法中,將我們設置的寬和高通過setMeasuredDimension來自定義VideoView的寬和高。
//設置全屏播放
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
mVideoView.setWidthHeight(metrics.widthPixels,metrics.heightPixels);
運行效果:

好,慕課網引導效果的編碼實現就到這。如果喜歡,請推薦一下。謝謝。
本文同時發表於慕課網手記頻道,並取得了40+個推薦以及首頁推薦的成績。歡迎各位支持推薦。

本文是由JohnTsai原創。著作權由本人保留。
如需轉載,請在顯著位置注明出處。
歡迎交流討論。
