androidviewpager自定义
A. android viewpager怎么用
一. 导入ViewPager第三方jar包android-support-v13.jar
在开发之前先在已经创建好的应用程序工程中导入jar包,方法如下:
选中应用程序工程,在eclipse的菜单栏选择Project->properties->java Build Path->Libraries->Add External Jars中加入已经下载好的jar包。加入这个jar包之后就可以使用ViewPager类来开发相关的应用了。
举一反三,其它第三方jar包的添加应该也是走这个步骤。
二. ViewPager的使用
下面以一个简单的demo来实现ViewPager的使用,该Demo的效果图如下:
该Demo总共四个页面,每个页面用一个Fragment来实现,所以分别创建FirstFragmentPage、SecondFragmentPage、ThirdFragmentPage、ForthFragmentPage四个类来实现四个页面,这个四个类都继承Fragment。这四个Fragment将在MainActivity中添加处理。以下主要代码实现:
1. 主布局文件main.xml代码如下:
[html] view plain
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<!-- ViewPager界面布局 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dip" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 指示图标和按钮的布局 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical" >
<!-- ViewPager界面下方的指示翻页图标 -->
<LinearLayout
android:id="@+id/indicator_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:gravity="center"
android:orientation="horizontal" >
</LinearLayout>
<!-- 底部的后退和前进按钮布局 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="30dip"
android:paddingRight="30dip" >
<Button
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/back" />
<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/next" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
2. MainActivity:
[java] view plain
package com.stevenhu.vpt;
import java.util.ArrayList;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity implements OnClickListener
{
private final static String TAG = "MainActivity";
private ViewPager mViewPager;
private ViewPagerAdapter mViewPagerAdapter;
private LinearLayout mIndicatorGroup;
//定义指示翻页图标数组
private ImageView[] mIndicatorImage;
private Button mBackButton, mNextButton;
//定义当前在第几页
private int mCurrentPage = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mViewPager = (ViewPager)findViewById(R.id.viewpager);
//创建自定义的ViewPagerAdapter对象
mViewPagerAdapter = new ViewPagerAdapter(this, mViewPager);
//添加Fragment
mViewPagerAdapter.addFragment(FirstFragmentPage.class, null);
mViewPagerAdapter.addFragment(SecondFragmentPage.class, null);
mViewPagerAdapter.addFragment(ThirdFragmentPage.class, null);
mViewPagerAdapter.addFragment(ForthFragmentPage.class, null);
//获取指示器图标所在界面布局对象
mIndicatorGroup = (LinearLayout)findViewById(R.id.indicator_group);
mIndicatorImage = new ImageView[mViewPagerAdapter.getCount()];
mBackButton = (Button)findViewById(R.id.back_button);
mNextButton = (Button)findViewById(R.id.next_button);
mBackButton.setOnClickListener(this);
mNextButton.setOnClickListener(this);
initIndicator();
}
//初始化指示器,实现随着创建页数的增加从而添加相应个数的指示图标。
private void initIndicator()
{
for (int i = 0; i < mViewPagerAdapter.getCount(); i ++)
{
ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(20,20));
imageView.setPadding(20, 0, 20, 0);
if (i == 0)
{
imageView.setBackgroundResource(R.drawable.page_indicator_focused);
}
else
{
imageView.setBackgroundResource(R.drawable.page_indicator);
}
mIndicatorImage[i] = imageView;
mIndicatorGroup.addView(mIndicatorImage[i]);
}
}
http://blog.csdn.net/stevenhu_223/article/details/8024925
B. Android ViewPager 控制滑动速度
参考 《ViewPager smoothScroll 速度控制》 ,很不错的文章,用Kotlin改写记录如下:
自定义滑动控制类,以实现自定义滑动
在自定义ViewPager中,通过反射,更改原生滑动控制类为自定义类
附ViewPager源码:
见 自适应高度(最低高度为屏幕高度) & 横屏闪退不拉长页面 & 自定义滑动速度
C. android 自定义view可以用在viewpager上吗
一部分:自定义ViewGroup的使用,手势识别器和Scroller滑动
第二部分:处理滑动监听,处理滑动冲突,增加ViewPager的指示器
基础概念:
常见的滑动冲突:外部滑动方向和内部滑动方向不一致、外部滑动方向和内部滑动方向一致。
我们自定义的ViewPager如果在其中一页中存在ListView,那么就需要解决滑动冲突的问题。
由于系统自带ViewPager中,自己已经解决了滑动冲突。
D. Android (基础自定义组件)viewpagertap滑动器
视频地址: http://www.imooc.com/learn/615
2.1.1主要定义画笔、三角形使用path来实现。接着定义三角形的大小(宽高)以及初始化位置。
2.1.2设置mInitTranslationX参数,表示三角形初始化的位置,相当于marginLeft,计算方式是:
mInitTranslationX = 一个tab的宽度 - 三角形宽度的/2
2.1.3设置mTranslationX参数,表示每一移动一个tab时,三角形需要平移的宽度,如图:
2.1.4 mTabVisibleCount,自定义属性,布局中要显示几个tab,如上图4个tab
2.2.1构造中主要获取自定义属性值,默认为4;以及设置画笔
2.3.1三角形的宽度 = 一个tab宽度的1/6;如果觉得宽度的大小不合适, 可以改变1/6这个常量的比例
2.3.2三角形的高度 = 高度/2如图:
2.4.1重写父类dispatchDraw方法,此方法在invalidate()时,会重新执行
2.4.2通过 canvas.translate()设置三角形所在位置;X轴(上去看2.1.3),Y轴为但前组件的高度(最底部)。以及调用drawPath()方法使用画笔。
2.5.1如标题主要是通过viewpager的position和positionOffset来计算mTranslationX的值;再通过scrollTo方法来平移但前组件,最后通过invalidate()方法重绘布局
2.5.2剩下的就是一些算法和逻辑判断
2.6.1获取viewpager,监听viewpager的滑动事件,自定义setScroll方法(2.5的方法)将但前position和滑动偏移量传进去
2.6.2在此次以及监听的viewpager的滑动事件,如果外界也需要监听当前viewpager的话,会起冲突;此时就需要设置回调,对外提供接口
2.6.3setTextHighLight()方法设置选中的tab为高亮颜色
2.7.1获取list集合,将每一个item设置成一个textview,再通过setTextItemOnclickEvent()方法设置点击事件
3.1app:visible_tab_count自定义属性;如果不设置默认为自定义组件的COUNT_TAB_VISIBLE变量值
http://pan..com/s/1qYGUTAW
http://pan..com/s/1slpi5v3
E. android viewpager如何动态添加页面
动态创建Adapter即可。ViewPager的数据是通过PageAdapter来装载的,刷新数据的方法有以下:
1. 调用adapter.notifyDataSetChanged(); 刷新控件,但是要覆盖PagerAdapter的getItemPosition方法,并返回 return POSITION_NONE;
2. 利用PagerAdapter的工作机制,就是PagerAdapter的执行顺序, PagerAdapter作为ViewPager的适配器,无论ViewPager有多少页,PagerAdapter在初始化时也只初始化开始的2个View,即调用2次instantiateItem方法。而接下来每当ViewPager滑动时,PagerAdapter都会调用destroyItem方法将距离该页2个步幅以上的那个View销毁,以此保证PagerAdapter最多只管辖3个View,且当前View是3个中的中间一个,如果当前View缺少两边的View,那么就instantiateItem,如里有超过2个步幅的就destroyItem。
3. 每当Adapter调用instantiateItem时,运用View.setTag方法将该View标识。当需要更新这个View的数据时,通过调用ViewPager.findViewWithTag方法找到相应的View,然后更新View中的数据。
F. android中在弹出的对话框中如何加viewpager
AlertDialog.Builderbuilder=newBuilder(this);
builder.setPositiveButton("确认",newOnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
dialog.dismiss();
finish();
}
});
builder.setNegativeButton("取消",newOnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
dialog.dismiss();
}
});
//填充布局
Viewinflate=LayoutInflater.from(this).inflate(R.layout.viewpager_layout,null);
...........
//setView这个方法把填充好的布局添加到对话框中
builder.setView(inflate);
builder.create().show();
G. Android-ViewPager源码解析与性能优化
ViewPager高度设置为wrap_content或者具体的高度值无效,是因为ViewPager的onMeasure方法在度量宽高的时候,在方法体的最开始就直接调用了setMeasuredDimension()方法将自身的宽高度量,但是并没有在其onMeasure()计算完其具体的子View的宽高之后,重新度量一次自身的宽高
从这里我们可以看到,ViewPager的宽高会受其父容器的宽高的限制,但是并不会因为自身子View的宽高而影响ViewPager的宽高。
看setMeasuredDimension的源码调用可以看出,当父容器的高度确定时,ViewPager的宽高其实就是父容器的宽高,ViewPager就是在onMeasure方法一进来的时候就直接填充满整个父容器的剩余空间。在计算孩子节点之前,就已经计算好了ViewPager的宽高,在计算完孩子节点之后,并不会再去重新计算ViewPager的宽高。
自定义一个ViewPager,根据子View的宽高重新度量ViewPager的宽高。其实做法就是在自定义onMeasure的super.onMeasure(widthMeasureSpec, heightMeasureSpec);之前重新计算heightMeasureSpec,将原本ViewPager接收的父容器的限定的heightMeasureSpec替换成我们自定义的heightMeasureSpec。
但是这样的做法,会有种问题,即在ViewPager的子View是采用LinearLayout作为根布局的时候,并且给LinearLayout设置了固定的高度值,那么会出现ViewPager动态高度无效的问题
其实具体的做法,就是仿造measureChild的做法,自定义子View的heightMeasureSpec然后度量整个子View,其实子View的宽度也可以这样做。
这里其实是源码层做了限制,在setOffscreenPageLimit中设置了一个默认值,而这个默认值的大小为1
所以从这里可以看出,ViewPager的最小缓存的limit是1,而不能小于1,当小于1的时候就会被强制的设置为1。
而populate()函数就是用来处理ViewPager的缓存的。
populate()的生命周期是与Adapter的生命周期绑定的。
其实在setOffscreenPageLimit()的时候,调用的populate(),而populate()内部调用的
而pupulate(int newCurrentItem)方法在另一处调用的地方就是在setCurrentItem。
其实ViewPager缓存都是基于ItemInfo这个类来进行的,
看下ViewPager.addNewItem的源码
其实ViewPager.addNewItem就是通过调用Adapter.instantiateItem来创建对应的View,并且将View保存到ItemInfo中的object属性,并且判断ViewPager缓存中是否已经有ItemInfo,如果没有,则添加,如果有则做修改替换
从分析FragmentStatePagerAdapter来看,setUserVisibleHint方法会优先于Fragment的生命周期函数 执行。因为在FragmentStatePagerAdapter中提交事务,是在调用finishUpdate方法中进行的,只有提交事务的时候,才会去执行Fragment的生命周期。
FragmentStatePagerAdapter中的instantiateItem和destroyItem都实现了对fragment的事务的添加和删除,而finishUpdate实现了事务的提交,所以在实现FragmentStatePagerAdapter的时候,并不需要重写instantiateItem和destroyItem
H. Android 用自定义高度自适应的viewpager,在进行滑动的时候滑动很不顺畅,有时根本划不动,求大神帮忙下
自已重写ViewPager就行了在onMeasure里做一下处理就可以实现自适应高度了.
主要是重写onMeasure方法来实现的。源代码已上传附件。