效果图如下:
ViewPager+Fragment添加一行若干小红球滚动指示器指示当前ViewPager翻阅位置(可供第三方使用的类)。
类似现在通用的新闻客户端头部,会放置几张图片供新闻阅读者翻阅,同时放置一行小圆球根据用户翻阅的位置相应的滚动,标识出当前第几页。
该项目开放出几个用以重载的方法函数供第三方使用:
protected Fragment getFragmentAt(int pos) { return null; } protected int getItemsCount() { return 0; } protected String getDescriptionAt(int pos){ return null; }
测试用的主MainActivity.java (不是重点,仅仅用以测试)
package zhangphil.viewpager_fragment; import java.util.ArrayList; import java.util.Random; import com.example.viewpager_fragment.R; import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Fragment newFragment = new HowToUseThisView(); FragmentTransaction transaction = getSupportFragmentManager() .beginTransaction(); transaction.replace(R.id.fragment, newFragment); transaction.commit(); } public static class HowToUseThisView extends ViewPagerAndFragmentWithCircleIndicator { private ArrayList<Fragment> mArrayList; // 主要用以标记Fragment,没特别意义 private int id = 0; // ViewPager的元素个数。 private int item_count = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mArrayList = new ArrayList<Fragment>(); // 测试用的。假设生成随机个数的Fragment。 Random rand = new Random(); item_count = rand.nextInt(10); } @Override protected Fragment getFragmentAt(int pos) { Fragment fragment = null; try { fragment = mArrayList.get(pos); } catch (Exception e) { Log.d(this.getClass().getName(), "队列中不存在,创建新Fragment"); } if (fragment == null) { fragment = new TestFragment(); ((TestFragment) fragment).setID(id++); mArrayList.add(fragment); } return fragment; } @Override protected int getItemsCount() { return item_count; } @Override protected String getDescriptionAt(int pos) { //实际使用过程中,可根据每个不同的Fragment返回不同的描述文本 return pos + ""; } } // // 仅仅用于测试的Fragment,在ViewPager中加载 // public static class TestFragment extends Fragment { private int id = 0; public void setID(int id) { this.id = id; } public int getID() { return id; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView tv = new TextView(getActivity()); String str = "序号: " + getID(); tv.setTextColor(Color.LTGRAY); tv.setText(str); tv.setTextSize(60); tv.setGravity(Gravity.CENTER); return tv; } } }
MainActivity.java所要的布局文件 activity_main.xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <FrameLayout android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout>
重点是 ViewPagerAndFragmentWithCircleIndicator.java
package zhangphil.viewpager_fragment; import com.example.viewpager_fragment.R; import zhangphil.libs.view.CircleIndicatorView; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class ViewPagerAndFragmentWithCircleIndicator extends Fragment { private MyFragmentPagerAdapter mPagerAdapter; private ViewPager mViewPager; private CircleIndicatorView mCircleIndicatorView; private TextView circleIndicatorView_TextView; private Handler handler; private final int MESSAGE_WHAT_DRAW_CIRCLE = 100; public void notifyDataSetChanged() { mPagerAdapter.notifyDataSetChanged(); } protected Fragment getFragmentAt(int pos) { return null; } protected int getItemsCount() { return 0; } protected String getDescriptionAt(int pos){ return null; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View mView = inflater.inflate(R.layout.viewpager_fragment, null); mViewPager = (ViewPager) mView.findViewById(R.id.viewpager); mPagerAdapter = new MyFragmentPagerAdapter(getFragmentManager()); mViewPager.setAdapter(mPagerAdapter); mViewPager .setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int pos) { set(pos); } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } }); mCircleIndicatorView = (CircleIndicatorView) mView .findViewById(R.id.circleIndicatorView); mCircleIndicatorView.drawCircleView(mPagerAdapter.getCount(), 0); //初始化红色小圆球的 位置和文本描述 circleIndicatorView_TextView=(TextView) mView.findViewById(R.id.circleIndicatorView_TextView); circleIndicatorView_TextView.setText(getDescriptionAt(0)); handler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MESSAGE_WHAT_DRAW_CIRCLE: mCircleIndicatorView.drawCircleView(mPagerAdapter.getCount(),mViewPager.getCurrentItem()); break; } }; }; return mView; } private void set(int pos) { mViewPager.setCurrentItem(pos, true); circleIndicatorView_TextView.setText(getDescriptionAt(pos)); handler.sendEmptyMessage(MESSAGE_WHAT_DRAW_CIRCLE); } private class MyFragmentPagerAdapter extends FragmentPagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int pos) { return getFragmentAt(pos); } @Override public int getCount() { return getItemsCount(); } @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); handler.sendEmptyMessage(MESSAGE_WHAT_DRAW_CIRCLE); } } }
ViewPagerAndFragmentWithCircleIndicator.java需要的布局文件 viewpager_fragment.xml :
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <FrameLayout android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="30dip" android:orientation="horizontal" android:layout_gravity="bottom" > <TextView android:id="@+id/circleIndicatorView_TextView" android:layout_width="0dip" android:layout_height="match_parent" android:gravity="left" android:textColor="#FF0000" android:layout_weight="1" android:singleLine="true" android:text="" /> <zhangphil.libs.view.CircleIndicatorView android:id="@+id/circleIndicatorView" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="0.382"/> </LinearLayout> </FrameLayout> </LinearLayout>
以及用以绘制红色小圆球的 CircleIndicatorView.java
package zhangphil.libs.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; public class CircleIndicatorView extends View { public CircleIndicatorView(Context context, AttributeSet attrs){ super(context, attrs); } private int gap=20;//各个横向排列的小球间距 public void setCirlceGap(int gap){ this.gap=gap; } public int getCirlceGap(){ return gap; } private int padding=20; public void setPadding(int padding){ this.padding=padding; } public int getPadding(){ return padding; } private int circle_normal_radius=5; //普通小球半径 public void setNormalCircleRadius(int radius){ this.circle_normal_radius=radius; } public int getNormalCircleRadius(){ return circle_normal_radius; } private int circle_selected_radius=7; //被选择的小球半径 public void setSelectedCircleRadius(int radius){ this.circle_selected_radius=radius; } public int getSelectedCircleRadius(){ return circle_selected_radius; } private int count=0; public void setCircleCount(int count){ this.count=count; } public int getCircleCount(){ return count; } private int pos=0; public void setCircleSelectedPosition(int pos){ this.pos=pos; } public int getCircleSelectedPosition(){ return pos; } public void drawCircleView(){ this.invalidate(); } public void drawCircleView(int count,int circleSelectedPosition){ setCircleCount(count); setCircleSelectedPosition(circleSelectedPosition); this.invalidate(); } private int circleSelectedColor=Color.RED; public void setCircleSelectedColor(int color){ circleSelectedColor=color; } public int getCircleSelectedColor(){ return circleSelectedColor; } private int circleUnSelectedColor=Color.LTGRAY; public void setCircleUnSelectedColor(int color){ circleUnSelectedColor=color; } public int getCircleUnSelectedColor(){ return circleUnSelectedColor; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint p = new Paint(); p.setAntiAlias(true); int w=this.getWidth(); int h=this.getHeight(); //因为是自右往左绘制小圆圈,需要转化pos的位置。 int translate_pos=getCircleCount()-getCircleSelectedPosition()-1; //如果居中绘制则使用start_x,但需要依次递加x坐标轴位置值。 //int start_x=(w-(CIRCLE_GAP*(getCircleCount()-1)))/2; for(int i=0;i<getCircleCount();i++){ int r=getNormalCircleRadius(); if(i==translate_pos){ r=getSelectedCircleRadius(); p.setColor(getCircleSelectedColor()); } else{ r=getNormalCircleRadius(); p.setColor(getCircleUnSelectedColor()); } //自右向左绘制。从最右边往左边绘制小球 //如果从该自定制的View左边绘制,直接将 x=0即可。 canvas.drawCircle(w-i*getCirlceGap()-getPadding(), h/2, r, p); } } }