好久没写博客了,今天没事怒更一记。
如标题今天我们来模仿一下搜狐新闻,先上个效果图.
效果图上完之后再上个博客,我也是从这里得到的启发http://blog.youkuaiyun.com/qibin0506/article/details/42046559
1,接下来我们就来分析一下这个效果
下面的内容应该是用viewpager,头部的选项卡我们用一个LinearLayout+HorizontalScrollView也可以实现,滚动效果的话我们可以用到我们学会的scrollTo,大致的思路理清,我们就开始码代码吧!
2,自定义LinearLayout
我们可以观察到那个红色的矩形应该是和整体的LinearLayout在一起,所以我们可以自定义LinearLayout画出那个矩形,滚动就是改变画矩形的位置即可
<span style="font-size:14px;">public class ViewpagerIndicator extends LinearLayout {
/**
* 画笔,底部矩形
*/
private Paint paint;
/**
* 子View个数
*/
private int mCount;
private int mTop;
private int mWidth;
private int mLeft;
private int mHeight = 5;
public OnTextClick onTextClick;
public ViewpagerIndicator(Context context) {
super(context);
}
public ViewpagerIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.TRANSPARENT);
paint = new Paint();
paint.setColor(getResources().getColor(R.color.red));
paint.setAntiAlias(true);
}
public interface OnTextClick{
public void textViewClick(int position);
}
public void setOnTextClick(OnTextClick onTextClick){
this.onTextClick = onTextClick;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//整体高度
mTop = getMeasuredHeight();
//整体宽度
int width = getMeasuredWidth();
//加上指示器高度
int height = mTop + mHeight;
//指示器的宽度
mWidth = width / mCount;
setMeasuredDimension(width, height);
}</span>
在onMeasure中我们拿到我们想要的关于位置距离的值,接下来我们就可以在onDraw中画出想要的矩形了
<span style="font-size:14px;">/**
* 画出指示器
* @param canvas
*/
protected void onDraw(Canvas canvas) {
Rect rect = new Rect(mLeft, mTop, mLeft + mWidth, mTop + mHeight);
canvas.drawRect(rect, paint);
}</span>
没错,就是俩句代码,之后通过不断的改变left就可以实现跟随滚动的效果。
<span style="font-size:14px;"> /**
* 滚动效果
* @param position
* @param positionOffset
*/
public void scrollTo(int position, float positionOffset) {
mLeft = (int) ((position + positionOffset) * mWidth);
postInvalidate();
}</span>
方法中的俩个参数我们可以通过viewpager的回调方法onPageScrolled中得到,position就是当前的选项卡,positionOffset相当于滑动的百分比0.0~0.0之间.
3,使用自定义控件
ok,大致的思路都已经理清,接下来我们就可以使用自己做的Indicator了。
<span style="font-size:14px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="topnews.inhome.wrh.fragment.NewsFragment">
<HorizontalScrollView
android:id="@+id/horizon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
>
<com.wrh.sohunews.ViewpagerIndicator
android:id="@+id/indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp"
android:text="首页"
android:textColor="@color/red"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="订阅"
android:layout_margin="10dp"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="娱乐"
android:layout_margin="10dp"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp"
android:text="本地"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp"
android:text="生活"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="军事"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="财经"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="社会"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="汽车"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="体育"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="历史"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="搞笑"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_margin="10dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="情感"
android:gravity="center" />
</com.wrh.sohunews.ViewpagerIndicator>
</HorizontalScrollView>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/horizon"
/>
</RelativeLayout></span>
先不要被眼前多如狗的TextView吓到,其实都是粘贴复制上去的改了一个text就行,我们也可以在自己的LinearLayout中通过TextView t = new TextView();然后add进去,这俩种方法都可以。
但是我们显然都不想给这么多的textview都取id然后拿到它的实例再setOnClick,所以我们就可以在自定义的ViewGroup中直接set
<span style="font-size:14px;">@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCount = getChildCount();
/**
* 监听点击事件,回调接口
*/
for (int i = 0 ;i<mCount;i++){
View view = getChildAt(i);
if (view instanceof TextView)
{
final int finalI = i;
((TextView) view).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onTextClick != null) {
onTextClick.textViewClick(finalI);
}
}
});
}
}
}</span>
通过回调接口我们就轻易的拿到了所点击的是哪一页选项卡,接下来我们来看看使用方法
<span style="font-size:14px;">public class MainActivity extends Activity implements ViewPager.OnPageChangeListener,ViewpagerIndicator.OnTextClick{
private ViewPager viewPager;
private int lastX = 0;
private ViewpagerIndicator indicator;
private HorizontalScrollView horizontalScrollView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
viewPager = (ViewPager) findViewById(R.id.viewpager);
indicator = (ViewpagerIndicator) findViewById(R.id.indicator);
indicator.setOnTextClick(this);
horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizon);
viewPager.setAdapter(new MyAdapter());
viewPager.setOnPageChangeListener(this);
}</span>
一些必要的实例化.
<span style="font-size:14px;"> /**
* 只有当从第一项滚动第二项或者从第二项滚动第一项时,整体不动指示器单独滚动,其余都是整个布局滚动
* @param position
* @param positionOffset
* @param positionOffsetPixels
*/
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (!(position == 0 && positionOffset - lastX >= 0) || !(position == 1 && positionOffset - lastX <= 0)){
horizontalScrollView.scrollTo((int)((positionOffset+position-1)*indicator.getIndicatorWidth()), 0);
}
indicator.scrollTo(position, positionOffset);
lastX = (int) positionOffset;
}
@Override
public void onPageSelected(int position) {
indicator.resetTextViewColor();
indicator.setFocusTextView(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}</span>
通过观察搜狐新闻我们可以看到,当从第一页滑动到第二页时,只有Indicator滚动了,之后都是整体滚动,所以我们要做好判断,整体滚动的时候indicator就相当于停留在了显示出来的第二个选项卡,接下来我们看看实际效果.
效果还是阔以的嘛,咔咔。