这个东西可能没什么好讲的,但是这个和正常的有点不一样。正常的是你到了这个view,底部的小点就会切换,颜色就会改变。这里是有一个伴随ViewPager滑动的点,根据ViewPager滑动的百分比也对应滑到这些若干点中响应的位置。
其实这个看似简单,并没有那么好实现。下面讲一下实现方案:
ViewPager开放了一个滑动时的监听方法
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {第一个position就是当前在哪个页面,第二个positionOffset就是当前偏移的百分比,在0-1之间变化,所以position+positionOffset就是0-5之间变化了,这一点很重要,这一点没理解,这个东西做不出来。
所以你接下来你需要计算每两个点的距离x,x乘以position+positionOffset+第一个点的左边距就是你这个点当前的横坐标了。所以你就可以用layout方法修改他的位置了
但是修改了还不行,由于重绘机制的存在,你必须修改布局参数才行。不然会发现,过一会就会复位。
github地址:https://github.com/xubinhong/WeChat2(在emojiFragment里)
package com.example.wechat.chat; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import com.example.wechat.R; import com.example.wechat.base.BaseFragment; import java.util.ArrayList; import java.util.List; import butterknife.BindView; /** * 第三次更新2017/12/22 完成了emoji相关,那个底部黑色dot,本来想属性动画,但是必须是跟随手指滑动的,所以还必须自定义控件(其实有点类似于view pager和tab host的绑定) **/ public class EmojiFragment extends BaseFragment { @BindView(R.id.vp_emoji) ViewPager mVpEmoji; // TODO: 2017/12/21 把emoji的滑动和那个黑点的滑动关联起来就好了,简单明白了!只需要在vp的监听事件里算出来移动的距离就可以了,在获取屏幕的长度,取得比例给底部的黑点。黑点是自定义控件。 List<View> viewList = new ArrayList<>(); @Override protected void initData() { if (viewList.size() == 0) {//之所以这样判断是因为我发现在闪电运行的时候,重了 for (int i = 0; i < 6; i++) { View v = LayoutInflater.from(getActivity()).inflate(R.layout.all_emoji, null, false); viewList.add(v); } } // TODO: 2017/12/22 onCreate的时候控件还没有渲染完,所以不管怎么取坐标,都是0 } private float dotDistance; private float realPos;//0-5 private float dotStartLeftPos; private float dotStartRightPos; private View dotView; @Override protected void initWidget(final View mRoot) { mVpEmoji.setAdapter(new MyAdapter(viewList)); mVpEmoji.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { //看到这个positionOffset的输出值我就知道已经搞定了,它代表了滑动的比例 //接下来需要取得两个按钮之间的距离,以第一个按钮和第二个按钮为参照。取得孩子,再取得左边距离就可以了 //还要在一开始明确一个方向,判断滑动方向也是一个问题,主要分界的时候太难判断了,(哎,观察的太不仔细了),分界的时候,如果往左,会突然变到0.9几的,我只需要把positionOffset通过数学的方式处理成0-5就可以了,如果减了1(粗略点就是大了0.8)就代表是右移,需要+1,如果加了1,就代表是左移 if (dotDistance == 0.0f) { ViewGroup vg = (ViewGroup) mRoot; ViewGroup vg2 = (ViewGroup) vg.getChildAt(1); View v1 = vg2.getChildAt(0); View v2 = vg2.getChildAt(1); dotDistance = v2.getLeft() - v1.getLeft(); dotStartLeftPos = v1.getLeft(); dotStartRightPos = v1.getRight(); dotView = vg.getChildAt(2); } //为什么会有一个缩到0的操作,可能是因为 realPos = positionOffset + position;//一行代码就搞定了!爽。和我的+1,-1效果一样 Log.i("xbh", realPos + ""); if (dotDistance != 0.0f) { float dotLeftPos = dotDistance * realPos + dotStartLeftPos; float dotRightPos = dotDistance * realPos + dotStartRightPos; //很严重的问题就是移动了位置没改变,因为布局参数没改变,然后应该去改变布局参数 dotView.layout((int)dotLeftPos, dotView.getTop(), (int)dotRightPos , dotView.getBottom()); RelativeLayout.LayoutParams lpFeedback = new RelativeLayout.LayoutParams( 13, 13); lpFeedback.setMargins(dotView.getLeft(), dotView.getTop(), 0, 0); dotView.setLayoutParams(lpFeedback); } } @Override public void onPageSelected(int position) {//页面变动,才会执行 //给那个dot一个属性动画,平移到对应第几个 } @Override public void onPageScrollStateChanged(int state) { } }); } @Override protected int getLayoutId() { return R.layout.fragment_emoji; } private class MyAdapter extends PagerAdapter { private List<View> list; MyAdapter(List<View> list) { this.list = list; } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(list.get(position)); return list.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(list.get(position)); } } }