tandroid -- 引导界面的原理与实现。
引导界面的实现逻辑:
首先通过startactivity进行进入程序的判断,如果是第一次登陆的话,就进入引导界面,如果不是,就进入登陆界面。
引导界面的实现,通过实现pageradapter来实现。判断是否第一次登陆通过sharedpreference来实现。在同一个包内,可以使用sharedpreference变量。
pageradapter必须添加两个参数,一个是List<View>,另一个是activity。
View是什么,View是界面。即layout布局,也就是用xml文件表示。
关于viewpager几行重要的代码:
Pageradapter必须绑定一个活动
vpAdapter = new ViewPagerAdapter(views, this);
vp = (ViewPager) findViewById(R.id.viewpager)
为viewpager绑定一个适配器
vp.setAdapter(vpAdapter);
为viewpager添加滑动事件
vp.setOnPageChangeListener(this);
这里附加一点其他的知识:
主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了.,来解决这个复杂的问题 , 由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
在startActivity中就使用到了handler,代码如下:
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case GO_HOME: goHome(); break; case GO_GUIDE: goGuide(); break; } super.handleMessage(msg); } };
接下来就是到了GuideActivity这个主要试下viewPager的活动。
在GuideActivity中要实现viewPager需要几个私有变量
private ViewPager vp;//ViewPager private GuideViewPagerAdapter vpAdapter; //适配器 private List<View> views; //适配器创建过程中需要活动与List<View>,然后将这个view放入到ViewAdapter
//记录点的ImageView
private ImageView[] dots;
//记录当前目录
private int currentIndex;
GuideActivity有一个自己的布局文件,然后向这个布局文件中添加ViewPager,就可以了。
来看一下guideActivity的总布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/ll" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="24.0dp" android:orientation="horizontal" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:clickable="true" android:padding="15.0dip" android:src="@drawable/dot" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:clickable="true" android:padding="15.0dip" android:src="@drawable/dot" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:clickable="true" android:padding="15.0dip" android:src="@drawable/dot" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:clickable="true" android:padding="15.0dip" android:src="@drawable/dot" /> </LinearLayout> </RelativeLayout>
在进入GuideActivity时,需要做两件事,就是
initViews();
initDots();
看一下initViews的代码和initDots代码。
private void initViews() { LayoutInflater inflater = LayoutInflater.from(this); views = new ArrayList<View>(); views.add(inflater.inflate(R.layout.guide_one, null)); views.add(inflater.inflate(R.layout.guide_two, null)); views.add(inflater.inflate(R.layout.guide_three, null)); views.add(inflater.inflate(R.layout.guide_four, null)); vpAdapter = new GuideViewPagerAdapter(views, this); vp = (ViewPager) findViewById(R.id.viewpager); vp.setAdapter(vpAdapter); vp.setOnPageChangeListener(this); } private void initDots() { LinearLayout ll = (LinearLayout) findViewById(R.id.ll); dots = new ImageView[views.size()]; for (int i = 0; i < views.size(); i++) { dots[i] = (ImageView) ll.getChildAt(i); dots[i].setEnabled(true); } currentIndex = 0; dots[currentIndex].setEnabled(false); }
当页面滑动之后,点也需要改变,这个时候要做的是就是重写GuideActivity一个方法
@Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stud
setCurrentDot(arg0); }
setCurrentDot写在GuideActivity中
private void setCurrentDot(int position) { if (position < 0 || position > views.size() - 1 || currentIndex == position) { return; } dots[position].setEnabled(false); dots[currentIndex].setEnabled(true); currentIndex = position; }
dot的使用不是一个难点,只要复制就可以了。在这里的核心技术是viewPager。实现这个例子的过程中结合guide的布局,实现一个页面中有banner不是一件难事了。
项目结构图
GuideActivity.java
package com.mypiece.start; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; public class GuideActivity extends Activity implements OnPageChangeListener{ private ViewPager vp; private GuideViewPagerAdapter vpAdapter; private List<View> views; //记录点的ImageView private ImageView[] dots; //记录当前目录 private int currentIndex; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_guide); initViews(); initDots(); } private void initViews() { LayoutInflater inflater = LayoutInflater.from(this); views = new ArrayList<View>(); views.add(inflater.inflate(R.layout.guide_one, null)); views.add(inflater.inflate(R.layout.guide_two, null)); views.add(inflater.inflate(R.layout.guide_three, null)); views.add(inflater.inflate(R.layout.guide_four, null)); vpAdapter = new GuideViewPagerAdapter(views, this); vp = (ViewPager) findViewById(R.id.viewpager); vp.setAdapter(vpAdapter); vp.setOnPageChangeListener(this); } private void initDots() { LinearLayout ll = (LinearLayout) findViewById(R.id.ll); dots = new ImageView[views.size()]; for (int i = 0; i < views.size(); i++) { dots[i] = (ImageView) ll.getChildAt(i); dots[i].setEnabled(true); } currentIndex = 0; dots[currentIndex].setEnabled(false); } @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } private void setCurrentDot(int position) { if (position < 0 || position > views.size() - 1 || currentIndex == position) { return; } dots[position].setEnabled(false); dots[currentIndex].setEnabled(true); currentIndex = position; } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int arg0) { // TODO Auto-generated method stub setCurrentDot(arg0); } }
GuideViewPagerAdapter.java
package com.mypiece.start; import java.util.List; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Parcelable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import com.mypiece.login.LoginActivity; public class GuideViewPagerAdapter extends PagerAdapter{ // 閻e矂娼伴崚妤勩�� private List<View> views; private Activity activity; //sharedpreference 可以实现同一个包内的使用 private static final String SHAREDPREFERENCES_NAME = "first_pref"; public GuideViewPagerAdapter(List<View> views, Activity activity) { this.views = views; this.activity = activity; } //删除某一项 @Override public void destroyItem(View arg0, int arg1, Object arg2) { ((ViewPager) arg0).removeView(views.get(arg1)); } @Override public void finishUpdate(View arg0) { } @Override public int getCount() { if (views != null) { return views.size(); } return 0; } //为引导界面最后一页点击按钮添加监视器 @Override public Object instantiateItem(View arg0, int arg1) { ((ViewPager) arg0).addView(views.get(arg1), 0); if (arg1 == views.size() - 1) { ImageView mStartWeiboImageButton = (ImageView) arg0 .findViewById(R.id.iv_start_weibo); //ImageView 也可以添加button事件。添加监视器。 mStartWeiboImageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 如果点击将其设置为不是第一次登陆,第一次的必须修改,之后的就没有必要 // 在点击事件中就会触发setGuided()事件。 setGuided(); goHome(); } }); } return views.get(arg1); } private void goHome() { // 跳转到登陆页面 Intent intent = new Intent(activity, LoginActivity.class); activity.startActivity(intent); activity.finish(); } /** * */ private void setGuided() { SharedPreferences preferences = activity.getSharedPreferences( SHAREDPREFERENCES_NAME, Context.MODE_PRIVATE); Editor editor = preferences.edit(); // 设置为是否第一次登陆 editor.putBoolean("isFirstIn", false); // 将其提交 editor.commit(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return (arg0 == arg1); } @Override public void restoreState(Parcelable arg0, ClassLoader arg1) { } @Override public Parcelable saveState() { return null; } @Override public void startUpdate(View arg0) { } }
StartActivity.java
package com.mypiece.start; import com.mypiece.start.R; import com.mypiece.start.R.layout; import com.mypiece.start.R.menu; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import com.mypiece.login.LoginActivity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Handler; import android.os.Message; public class StartActivity extends Activity { //检测是否第一册登陆的flag boolean isFirstIn = false; private static final int GO_HOME = 1000; private static final int GO_GUIDE = 1001; private static final long SPLASH_DELAY_MILLIS = 2000; private static final String SHAREDPREFERENCES_NAME = "first_pref"; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case GO_HOME: goHome(); break; case GO_GUIDE: goGuide(); break; } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_start); init(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.start, menu); return true; } private void init() { SharedPreferences preferences = getSharedPreferences( SHAREDPREFERENCES_NAME, MODE_PRIVATE); isFirstIn = preferences.getBoolean("isFirstIn", true); if (!isFirstIn) { mHandler.sendEmptyMessageDelayed(GO_HOME, SPLASH_DELAY_MILLIS); } else { mHandler.sendEmptyMessageDelayed(GO_GUIDE, SPLASH_DELAY_MILLIS); } } private void goHome() { Intent intent = new Intent(this, LoginActivity.class); this.startActivity(intent); this.finish(); } private void goGuide() { Intent intent = new Intent(this, GuideActivity.class); this.startActivity(intent); this.finish(); } }
这里需要的页面主要xml文件一共activity_start,activity_guide,activity_login这三个。
但是activity_guide还需要四个viewPager需要的页面xml文件。