main.xml
成都创新互联公司是专业的西安网站建设公司,西安接单;提供成都网站制作、做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行西安网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
先定义一个GridView,然后再定义一个ImageSwitcher
LinearLayout xmlns:android=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
GridView
android:id="@+id/gridView1"
android:layout_height="fill_parent"
android:layout_width="300px"
android:layout_marginTop="6px"
android:horizontalSpacing="3px"
android:verticalSpacing="3px"
android:numColumns="4"/
ImageSwitcher
android:id="@+id/imageSwicher1"
android:padding="20px"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/ImageSwitcher
/LinearLayout
MainActivity代码如下
public class MainActivity extends Activity {
private int[] imageId = new int[] { R.drawable.w1, R.drawable.w2,
R.drawable.w3, R.drawable.w4, R.drawable.w5, R.drawable.w6 };
private ImageSwitcher imageSwitcher;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwicher1);
imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));// 设置淡入动画
imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));// 设置谈出动画
imageSwitcher.setFactory(new ViewFactory() {
@Override
public View makeView() {
// TODO Auto-generated method stub
ImageView imageView = new ImageView(MainActivity.this);// 实例化一个ImageView类的对象
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);// 设置保持纵横比居中缩放图像
imageView.setLayoutParams(new ImageSwitcher.LayoutParams(// 主要要是用ImageSwitcher的LayoutParams
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
return imageView;
}
});
imageSwitcher.setImageResource(imageId[0]);
GridView gridView = (GridView) findViewById(R.id.gridView1);
BaseAdapter adapter = new BaseAdapter() {
/*
* 获得数量
*
* @see android.widget.Adapter#getCount()
*/
@Override
public int getCount() {
// TODO Auto-generated method stub
return imageId.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
/**
* 获得当前选项
*/
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(MainActivity.this);
/** 设置图像的宽度和高度 **/
imageView.setAdjustViewBounds(true);
imageView.setMaxWidth(150);
imageView.setMaxHeight(113);
imageView.setPadding(5, 5, 5, 5);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(imageId[position]);
return imageView;
}
};
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView? arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
imageSwitcher.setImageResource(imageId[arg2]);// 显示选中的图片
}
});
}
}
原文博客链接
用过 iOS 的都知道,拟物理的回弹效果在上面非常普遍,因为这是 iOS 系统支持的一套 UI 框架,但是 Android 就没有了,就拿图片查看器来讲,iOS 的效果就是感觉一张图片被绑定在了弹簧装置上,滑动很自然,Android 没有自带的图片查看器,需要自己实现
市面上主流的图片查看器都没有回弹的效果,一部分原因是没有这个需求,还有一部分是实现麻烦,这里讲述一个个人认为最好的方案
一个图片查看器,要求可以滑动 Fling,触碰到边界的时候回弹,有越界回弹的效果,支持双指缩放,双击缩放
咋一看需求,应该好写,滚动的时候用 Scroller 来解决,回弹效果直接用 ValueAnimator ,设置插值器为减速插值器来解决。看似简单,但是因为是仿物理效果,中间牵扯到从滚动到回弹的时候( Scroller 动画切换到 ValueAnimator 动画)的速度衔接问题,要看上去从滚动到开始回弹至结束没有突兀,中间的特判边界处理是很麻烦的,还要牵扯到缩放,所以不考虑这种方案
既然是要模拟现实中的物理效果,为何不在每一帧根据当前的状态得到对用的加速度,然后去计算下一帧的状态位置,这样只要模拟现实中的物理加速度不就可以实现了吗,那些边界特判之类的就可以去见阎王了
方案确定完毕,接下来就是选定加速度的方程,要模拟弹簧的效果,拉力很简单,用胡克定律嘛! F = k * dx ,摩擦力呢? Ff = μ*FN ? 这里推荐一个更加好的方案,借鉴自 Rebound 库,这是 Facebook 的一个弹簧动画库,设定一个目的数值,它会根据当前的拉力,摩擦力,速度然后变化到目标值,加速度方程为
其中 tension 为弹性系数, friction 为摩擦力系数,为什么让摩擦力和速度成正比呢?如果摩擦力和速度成正比,那么就不存在静摩擦力,也就是不存在物体静止情况下拉力小于摩擦力的情况(因为速度为0的时候,阻力为0,除非拉力为0),物体肯定会向目标地点靠近,遏制了物体摩擦力过大而无法达到目的地情况
为了方便接入各种 View ,设计一个 ZoomableGestureHelper 类
设计目的,我只需要知道视图的大小边界 (bounds) 和内部可滚动回弹的边界 (innerBounds),就可以通过计算得到一个新的转换矩阵
对于物理状态,需要一个类 SpringPhysicsState 来做存储,里面包含了速度、拉力系数、摩擦力系数,不保存位置,因为位置是通过 getBounds 动态计算得到的
速度分解成水平方向和垂直方向,因为处理方法一样,下面只讲述垂直方向的计算
状态1 :其中一边有越界
分析一下上图中的位置,蓝色部分为内部图片,它被拖动越界了,此时的合力应该为 tension * dx - friction * v , v 为图片在 y 轴方向上的速度,( dx 和 v 都是矢量,我暂且设置向右和向下为正),之后就直接调用 invalidate(); ,就可以播放动画了。
状态2:两边都没越界
此时因为两边都没有越界,所以应该不存在拉力,可以认为此时 dx 为0,摩擦力需要注意下,因为可以支持滑动( Fling ),所以此时的摩擦力要比之前越界回弹时候的摩擦力小,至于具体数值,文末会给出
状态3:两边都超出
此时两边都超出边界,蓝色区域应该和红色区域中心绑定,所以此时的 dx 为 dxBottom - dxTop (注意符号,因为 dx 为矢量,所以不能是 dxTop - dxBottom )
缩放的方法和移动一致,设定 tension 和 friction ,边界设定为外面红色的框框,蓝色区域无法某一边充满红色区域的时候,有拉力,否则没拉力,摩擦力一直存在,至于双击放大和放小,只需要在双击的时候给缩放状态设置一个初速度,然后 invalidate(); ,搞定!是不是很简单啊
时间这一个参数在计算中是非常重要的,这关系到当前微分状态的数值变化,假如用欧拉方法模拟速度和位置的变化, x' = x + v * dt , v' = v + a * dt ,公式可以看出时间决定了动画的快慢,为了接近现实物理时间,这里采用的时间单位为秒(计算机中常用的是毫秒)
确定了单位,还需要控制一下时间间隔的数值范围,我们不能让两次 computeScroll 的时间间隔过于短或者过于长,这里采用的策略为固定每次计算时候的时间间隔,如果两次 computeScroll 的时间间隔小于此时间间隔,那么保存累计时间间隔,等待下一次 computeScroll ,直到大于等于固定的时间间隔,再用 while 循环一步一步的计算
结束判定是唯一的一个坑,因为计算机只是在 dt 时间内模拟速度和位移的变化,不是通过微积分计算的,存在误差,比如欧拉方法 x' = x + v * dt 和 v' = v + a * dt 计算得到的 x' 和 v' 都是近似数值,把 dt 这段时间内的变化看成了匀变速运动
所以结束判定还需要设置一个阈值,当速度和偏移量小于此数值的时候,可以认定为达到了目的地
对于 ViewPager 的适配有些问题,如果在 Down 的时候 requestDisallow true 移动过程中到了左右边界又 requestDisallow false ,此时 ViewPager 会有一个突变( 突变可耻但有用 ),而且多指头的时候可能会崩溃,这是 ViewPager 的 Bug,具体细节请看源码
android 是linux内核,在文件系统中以.开头的文件或者文件夹都是隐藏文件,因此你可以这样隐藏:
只需要将这个目录的名称改成.开头 即可隐藏掉。
图库默认有这个功能,只要你长按就会弹出选项,选择隐藏即可
查看隐藏的相册,在选项选择显示隐藏的相册即可