Android ViewPager切换之PageTransformer接口中transformPage方法解析

今天让我们了解一下,Android3.0之后ViewPager切换时候的一个动画。Google给我们展示了两个动画例子:DepthPageTransformer和ZoomOutPageTransformer,代码如下:

public class DepthPageTransformer implements PageTransformer {
        private static float MIN_SCALE = 0.75f;
     
        @SuppressLint("NewApi")
        @Override
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            if (position < -1) { // [-Infinity,-1)//This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 0) { // [-1,0]Use //the default slide transition when moving to the left page
                view.setAlpha(1);
                view.setTranslationX(0);
                view.setScaleX(1);
                view.setScaleY(1);
            } else if (position <= 1) { // (0,1]// Fade the page out.
                view.setAlpha(1 - position);
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
                // Scale the page down (between MIN_SCALE and 1)
                float scaleFactor = MIN_SCALE + (1 - MIN_SCALE)
                        * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            } else { // (1,+Infinity]
                        // This page is way off-screen to the right.
                view.setAlpha(0);
     
            }
        }
     
    }
public class ZoomOutPageTransformer implements PageTransformer { 
        private static float MIN_SCALE = 0.85f; 
       
        private static float MIN_ALPHA = 0.5f; 
       
        @Override 
        public void transformPage(View view, float position) { 
            int pageWidth = view.getWidth(); 
            int pageHeight = view.getHeight(); 
       
            if (position < -1) { // [-Infinity,-1) 
                                    // This page is way off-screen to the left. 
                view.setAlpha(0); 
            } else if (position <= 1) { // [-1,1] 
                                        // Modify the default slide transition to 
                                        // shrink the page as well 
                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); 
                float vertMargin = pageHeight * (1 - scaleFactor) / 2; 
                float horzMargin = pageWidth * (1 - scaleFactor) / 2; 
                if (position < 0) { 
                    view.setTranslationX(horzMargin - vertMargin / 2); 
                } else { 
                    view.setTranslationX(-horzMargin + vertMargin / 2); 
                } 
                // Scale the page down (between MIN_SCALE and 1) 
                view.setScaleX(scaleFactor); 
                view.setScaleY(scaleFactor); 
                // Fade the page relative to its size. 
                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) 
                        / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); 
            } else { // (1,+Infinity] 
                        // This page is way off-screen to the right. 
                view.setAlpha(0); 
            } 
        } 
    } 

我们在使用的时候只需mPager.setPageTransformer(true, new DepthPageTransformer())即可,下面让我们看看transformPage方法怎么实现动画的!!!

transformPage方法有两个参数,第一个view当然就是应用动画的那个控件,第二个是一个float类型的值,不是我们平常见到的position位置,而是当前滑动状态的表示,相对于当前position的position。它有三个临界值-1 0 1,0代表当前屏幕显示的view的position,1代表当前view的下一个view所在的position,-1代表当前view的前一个view所在的position。不知道我讲清楚没有?

那么请看下面的图片:

下面让我们看看当前view左滑、右滑时各个view positon的变化情况:

好了,上面的表格大家可以通过打log的形式验证一下。知道了各个位置的view的position的变化情况,下面让我们看看动画吧。这里我们不做炫酷的动画,只做透明度的动画,方便大家理解transformPage方法。

前提不知道大家了不了解alpha这个属性,它的取值范围在0和1之间,0代表完全透明,1代表完全不透明。废话不多说看动画:

public class ViewpagerTransformAnim implements ViewPager.PageTransformer {
    @Override
    public void transformPage(View page, float position) {
        float alpha = 0.0f;
        if (0.0f <= position && position <= 1.0f) {
            alpha = 1.0f - position;
        } else if (-1.0f <= position && position < 0.0f) {
            alpha = position + 1.0f;
        }
        page.setAlpha(alpha);
    }
}

那么我们就对上面的代码简单的解释一下:不管当前view左滑还是右滑,当我滑动的时候,根据之前的表格我们知道上面的两个判断语句都会走到,这是因为你滑动的时候,肯定是两个view做动画的切换(不算两个边界,边界的话只会走一个),由于alpha取值在0和1之间,position取值在-1和1之间。所以有了条件语句中的代码。看下效果吧:

Can’t process attribute android:fillColor=”@android:color/white”: references to other resources are not supported by build-time PNG generation.

升级为android studio3.0,gradle升级为4.1,报错:

Can’t process attribute android:fillColor=”@android:color/white”: references to other resources are not supported by build-time PNG generation.

那是你需要在项目的build.gradle脚本中,增加对Vector兼容性的支持

解决方法:

使用Gradle Plugin 2.0以上:
android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}
使用Gradle Plugin 2.0以下,Gradle Plugin 1.5以上:

android {
    defaultConfig {
        // Stops the Gradle plugin’s automatic rasterization of vectors
        generatedDensities = []
    }
    // Flag to tell aapt to keep the attribute ids around
    aaptOptions {
        additionalParameters "--no-version-vectors"
    }
}

SensorManagerFlow: registerListenerImpl

SensorManagerFlow: registerListenerImpl
java.lang.Exception
at android.hardware.SystemSensorManager.registerListenerImpl(SystemSensorManager.java:118)
at android.hardware.SensorManager.registerListener(SensorManager.java:775)
at android.hardware.SensorManager.registerListener(SensorManager.java:682)
。。。。

 

之前发生这个问题是:注册监听时Activity已经finish掉了

 

 

解决Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com

这个问题是Android studio升级到3.0之后,运行的时候会提示gradle要升级到3.5版本才能编译。于是我把我的gradle升级到了

 gradle-4.1-milestone-1 版本,是2017年7月份最新版本了。
于是我把主程序的build.gradle中的gradle版本改成了这个,具体指定哪个版本我也不知道,于是就写了个3.0+
 dependencies {
classpath ‘com.android.tools.build:gradle:3.0+’

}

然后再次编译,又发现了毒。
提示:Error:All flavors must now belong to a named flavor dimension.Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
这个一个错误,意思是:所有的flavors都必须属于同一个风格。
=。=懵逼
去翻墙看了它提供的地址才知道:
 Plugin 3.0.0 includes a new dependency mechanism that automatically matches variants when consuming a library. This means an app’s debug variant automatically consumes a library’s debug variant, and so on. It also works when using flavors—an app’s redDebug variant will consume a library’s redDebug variant. To make this work, the plugin now requires that all flavors belong to a named flavor dimension —even if you intend to use only a single dimension. Otherwise, you will get the following build error:
  1. Error:All flavors must now belong to a named flavor dimension.
  2. The flavor ‘flavor_name’ is not assigned to a flavor dimension.
 To resolve this error, assign each flavor to a named dimension, as shown in the sample below. Because dependency matching is now taken care of by the plugin, you should name your flavor dimensions carefully. For example, if all your app and library modules use the foo dimension, you’ll have less control over which flavors are matched by the plugin.
  1. // Specifies a flavor dimension.  
  2. flavorDimensions “color”  
  3.   
  4. productFlavors {  
  5.      red {  
  6.       // Assigns this product flavor to the ‘color’ flavor dimension.  
  7.       // This step is optional if you are using only one dimension.  
  8.       dimension “color”  
  9.       …  
  10.     }  
  11.   
  12.     blue {  
  13.       dimension “color”  
  14.       …  
  15.     }  
  16. }  
大致是说,Plugin 3.0.0之后有一种自动匹配消耗库的机制,便于debug variant 自动消耗一个库,然后就是必须要所有的flavor 都属于同一个维度。
为了避免flavor 不同产生误差的问题,应该在所有的库模块都使用同一个foo尺寸。
= 。=还是懵逼。说一堆依然不是很理解。
但是我们从中已经知道解决方案了:
在主app的build.gradle里面的
 defaultConfig {
 targetSdkVersion:***
minSdkVersion :***
versionCode:***
 versionName :***
//版本名后面添加一句话,意思就是flavor dimension 它的维度就是该版本号,这样维度就是都是统一的了
flavorDimensions “versionCode”
}
就直接解决这个问题。然后app 就可以happy的运行起来了。

调用startActivityForResult后直接调用onActivityResult

人人都知道,可以通过使用 startActivityForResult() 和 onActivityResult() 方法来传递或接收参数。

但你是否遭遇过onActivityResult()不执行或者未按预想的那样执行的情况呢?

这里我总结了三种情况:

 

1、执行startActivityForResult,没等到被调用的 Activity 返回,onActivityResult() 就被执行了。
找了很久,终于通过小道消息得知,这与 Activity 的加载模式(launchMode)有关,该属性可以在 AndroidManifest.xml 中设置。
原先将其设为 singleInstance,经测试,所有需要传递或接收的 Activity 不允许设置该属性,或只能设为标准模式,否则系统将在 startActivityForResult() 后直接调用 onActivityResult()。

Note that this method should only be used with Intent protocols
    * that are defined to return a result.  In other protocols (such as
     {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
    
not get the result when you expect.  For example, if the activity you
    * are launching uses the singleTask launch mode, it will not run in your
    * task and thus you will immediately receive a cancel result.

总结:目标activity的launchmode不克不及设置成singleTask。
equestCode值>=0,不然,startActivityForResult就变成了 startactivity 

2、两个activity传递数据和返回数据时,请求方的onActivityResult始终无响应,通过debug调试模式也没见调用该方法。查看了各种配置和程序代码,均未发现有错误之处。后来仔细阅读API说明,恍然大悟,原来是调用startActivityForResult的参数问题,即调用时这样:
startActivityForResult(intent, 0);
是第二个参数的问题,该参数必须大于0才能在返回值,并激活onActivityResult方法。
我最开始是用的一个activity默认的常量:RESULT_OK,跟踪了代码后发现,该常量的值为-1,当然没法激活 onActivityResult方法了,随后随便修改为一个大于0的整数,程序即通跑成功。
startActivityForResult(intent, 1); //这样就行了

API描述:
@requestCode If >= 0, this code will be returned in  onActivityResult() when the activity exits.

3、在TabHost的子Activity中startActivityForResult调用其他Activity时候遭遇到onActivityResult方法不响应的问题.

可以通过调用Activity的getCallingActivity()查看要接受数据的Activity。

API这么解释的:

Return the name of the activity that invoked this activity.  This is
    * who the data in {@link #setResult setResult()} will be sent to.

举个列子,有两个ActivityA和B,A中执行startActivityForResult(1,new Intent(A,B.class));

即由A调到B,再B执行setResult后执行getCallingActivity(),显示A。

解决办法如下:

1.通过父Activity启动其他Activity;

2.实现父Activity的onActivityResult方法,将该处接收到的请求转发给当前活动的子Activity;

3.自定义一个转发接口用来实现第2步中的转发功能;

4.子Activity中实现第3步接口中的方法用来接收返回信息;

 

https://www.cnblogs.com/caoxinyu/p/6647801.html

http://blog.csdn.net/sodino/article/details/22101881

 

Android ImageView ScaleType:图解

如果你跟我一样追求美观界面,同时又非常健忘。当谈到ImageView缩放图片时,偏偏就把各种ScaleType的展示效果给忘了。所以你花了10~15分钟把每种效果都编译运行一遍看每种效果的异同。不久之后,这个循环又将发生一遍。

下面展示不同ScaleType的效果。接着是官方文档的解释,最后是一点有用的提醒。

Scale Types
完整的官方解释Android documentation.

CENTER

放中间,不拉伸。

CENTER_CROP

均匀拉伸(保持宽高比),宽高>=ImageView的宽高

CENTER_INSIDE

均匀拉伸(保持宽高比),宽高<=ImageView的宽高

FIT_CENTER

Matrix.ScaleToFit.CENTER来拉伸图片。
Matrix.ScaleToFit.CENTER:等比缩放,确保原图会整个放在View内,宽高至少有一个适配容器宽高,居中显示。

FIT_END

Matrix.ScaleToFit.END来拉伸图片。
Matrix.ScaleToFit.END:同上,底部显示。

FIT_START

Matrix.ScaleToFit.START来拉伸图片。
Matrix.ScaleToFit.START:同上,头部显示。

FIT_XY

Matrix.ScaleToFit.FILL来拉伸图片。
Matrix.ScaleToFit.FILL:原图完全填充容器,可能会改变宽高比。

MATRIX

Matrix旋转图片

调整边界

ImageView.ScaleType并不是万金油。如果你注意到赋值了CENTER_INSIDE, FIT_CENTER, FIT_ENDFIT_STARTImageView的实际边界往往都比缩放后的图片要大。如果要设置ImageView的宽高于缩放后的图片一致,在xml中添加

android:adjustViewBounds="true”

结果

TortoiseSVN客户端重新设置用户名和密码

办法一:在TortoiseSVN的设置对话框中,选择“已保存数据”,在“认证数据”那一行点击“清除”按钮,清楚保存的认证数据,再检出的时候就会重新跳出用户名密码输入框。

 

如果方法一不起作用,则可以采用方法二:

Tortoise的用户名密码等认证信息都是缓存在客户端文件系统的这个目录:

C:/Documents and Settings/Administrator/Application Data/Subversion/auth

删除auth下面的所有文件夹,重新连接远程服务器进行检出,对话框就会出现!