查看: 17096|回复: 13

[Android常见问题] 自定义授权界面

[复制链接]

Rank: 5Rank: 5

主题:
帖子:
积分:
0

[Android常见问题] 自定义授权界面

[复制链接]
17096 13 | 发表于 2014-10-24 14:03:47 |阅读模式 | |
本帖最后由 wolf 于 2016-5-6 10:30 编辑

自定义授权界面

AuthorizeAdapter的界面布局

AuthorizeAdapter的界面布局

1、准备工作

参考文档,在你的项目里面创建一个类,叫做MyAuthPageAdapter(或者其他你喜欢的名字),让这个类继承自“cn.sharesdk.framework.authorize.AuthorizeAdapter”,然后将这个类的完整路径(也就是包名+类名)注册到AndroidManifest.xml的ShareSDKUIShell这个Activity下。另外一些开发者虽然正确地编写和注册了这个AuthorizeAdapter,却忘记在混淆的时候keep这个类,导致这个类被改名甚至丢失。  

  1. <activity
  2.        android:name="com.mob.tools.MobUIShell"
  3.        android:theme="@android:style/Theme.Translucent.NoTitleBar"
  4.        android:configChanges="keyboardHidden|orientation|screenSize"
  5.        android:windowSoftInputMode="stateHidden|adjustResize" >
  6.        <!--
  7.               AuthorizeAdapter表示一个继承自cn.sharesdk.framework.authorize.AuthorizeAdapter
  8.               的类,这个类可以监听到页面的生命周期,也可以获取授权页面的各种UI控件。
  9.               开发者可以通过继承AuthorizeAdapter,重写其方法,并获取各种UI来自定义这个页面的行为。
  10.         -->        
  11.        <meta-data android:name="AuthorizeAdapter" android:value="cn.sharesdk.demo.MyAuthPageAdapter" />
  12. </activity>
复制代码

说明文档介绍了这个类的配置、各种和生命周期相关的方法的名称等等,虽然举了例子,但是很简单。不过Sample里面有一个很丰富的例子,而AuthorizeAdapter的JavaDoc也有对其public方法的定义说明,这些都建议看一下。下面对常见的一些问题做一下解释:

2、如何隐藏logo

授权页面其实没有那么复杂。虽然Share SDK的所有ui都依赖于ShareSDKUIShell,但是其实它只是提供一个外壳,其业务由具体的FakeActivity实现。Web授权的业务由FakeActivity的子类WebAuthorizeActivity实现,而这个类中有三个主要的成员AuthorizeAdapter、RegisterView和AuthorizeListener。其中的RegisterView和AuthorizeListener并不对外暴露,分辨用于表示授权页面的View,和授权操作的回调。因此自定义授权页面的操作,就是依赖WebAuthorizeActivity的生命周期,修改RegisterView的过程。

然后仔细看一下RegisterView。它是LinearLayout的子类,分为两部分——标题栏(TitleLayout)和页面主体(RelativeLayout)。TitleLayout也是LinearLayout的子类,它在授权页面的时候包含5个子View,第一个表示返回按钮,第二个是按钮后面分割线,第三个是标题栏上的文字,第四、第五个隐藏,你可以在快捷分享的EditPage里面看到它们,在右上角,最后的是Share SDK的logo。删除logo就是让这个view不可视,不过具体的代码下面再说,继续介绍页面主体。

页面主体是一个RelativeLayout,里面直接包含一个LinearLayout,之所以使用RelativeLayout,是为了后续自定义的扩展性更高,如果只有一个单纯的LinearLayout,开发者甚至不能在页面上摆多一个“悬浮”按钮。页面主体只有两部分,上面是一个View,其实是页面加载的进度条(一条蓝色的小条),然后绝大部分的面积被一个WebView覆盖,用来显示授权页面。有些开发者问“授权页面的样式能不能修改”。我不清楚他的“样式”是指什么,如果是控件的布局或者显示效果,答案是“可以”,如果是改变WebView里面的布局,答案是“不行”,因为这是个网页,是目标平台提供的页面。

说了这么多,怎么去除logo呢——看上去似乎很碍眼。代码是这样子的:

  1. public class MyAuthPageAdapter extends AuthorizeAdapter {
  2.          public void onCreate() {
  3.                    hideShareSDKLogo();
  4.          }
  5. }
复制代码

这段代码可以在Sample的MyAdapter中找到。这个方法2.0以前并不存在,因为那时候使用的是另外的代码:

  1. public class MyAuthPageAdapter extends AuthorizeAdapter {
  2.          public void onCreate() {
  3.                    TitleLayout llTitle = getTitleLayout();
  4.                     int count = llTitle.getChildCount();
  5.                     llTitle.getChildAt(count - 1).setVisibility(View.GONE);
  6.          }
  7. }
复制代码

这两种办法是等价的。

3、如何去掉启动动画

有些开发者不喜欢授权页面的弹出动画,希望去掉,具体的代码是这样子的:

  1. public class MyAuthPageAdapter extends AuthorizeAdapter {
  2.          public void onCreate() {
  3.                    disablePopUpAnimation();
  4.       }
  5. }
复制代码

这行代码也在Sample的MyAdapter中。

4、如何修改标题栏

很少有开发者需要修改标题栏上除了Logo以外的内容,不过前段时间确实有开发者问过,他想居中显示文字,而且想修改“返回按钮”的图片等等。那么现在回头看上面RegisterView的结构图。TitleLayout你可以从方法getTitleLayout()中获得,得到以后你可以修改它的背景、高度,甚至可视性。而修改返回按钮,你应该参考TitleLayout的JavaDoc,你会找到一个方法getBtnBack(),这个方法返回一个ImageView,就是返回按钮。通过setImageResource()方法可以修改其图标。至于如果你想去掉返回按钮后面的分割线,会麻烦一点,用下面的代码:

  1. public class MyAuthPageAdapter extends AuthorizeAdapter {
  2.          public void onCreate() {
  3.                    TitleLayout llTitle = getTitleLayout();
  4.                     llTitle.getChildAt(1).setVisibility(View.GONE);
  5.           }
  6. }
复制代码

为啥是“1”,参考上面的图片你就明白了。

然后是文字,同样有一个方法getTvTitle(),这个方法会返回标题栏的文字的控件。通过修改这个控件的各种属性,可以修改标题栏的样式。至于如何居中文字,其实这个TextView是设置比重为1的,因此它自动占满父容器。所以你只需要setGravity(Gravity.CENTER)就行了。但是这样子运行以后可能看上去不是很居中,那是因为返回按钮还有宽度。因此这个时候你还需要调用setPadding(0, 0, dp_48, 0);其中的dp_48表示“48dp”,是返回按钮的狂赌,其实你还可以更精确设置为“50dp”,因为分割线的宽度是“2dp”。

5、如何自定义动画

动画有利于页面加载,授权页面自己是有弹出动画的,但是如果你想设置自己的动画,该怎么做呢?先来看一下授权页面默认动画的设置代码:

  1. adapter.onCreate();
  2. if (adapter != null && !adapter.isPopUpAnimationDisable()) {
  3.        ScaleAnimation anim = new ScaleAnimation(0, 1, 0, 1,
  4.                 Animation.RELATIVE_TO_SELF, 0.5f,
  5.                 Animation.RELATIVE_TO_SELF, 0.5f);
  6.         anim.setDuration(550);
  7.         anim.setInterpolator(new PopUpInterpolator());
  8.         rv.setAnimation(anim);
  9. }
  10. activity.setContentView(rv);
复制代码

这段代码来自WebAuthorizeActivity的onCreate方法,其中的adapter是AuthorizeAdapter,rv是授权页面的最外层容器,授权页面的动画就是在这个View上面。

先解释一下这几行代码吧。adapter的onCreate会先调用,所以开发者可以在adapter的onCreate方法中对ui作显示前的最后修改。此后如果adapter里面被调用了disablePopUpAnimation方法,则跳过rv的动画设置,否则为rv设置一个ScaleAnimation,这个动画的时长是500毫秒,相对于中心缩放,缩放的规则由PopUpInterpolator控制(其内部是一个float数组而已)。然后就为ShareSDKUIShell设置View了。

开发者如果想自定义动画,需要做三件事情:禁用默认动画、获取授权页面顶级容器rv、为rv设置自己的动画。下面用Sample中的代码演示:
  1. public class MyAuthPageAdapter extends AuthorizeAdapter {
  2.          public void onCreate() {
  3.                    disablePopUpAnimation();
  4.                     View rv = (View) getBodyView().getParent();
  5.              TranslateAnimation ta = new TranslateAnimation(
  6.              Animation.RELATIVE_TO_SELF, -1,
  7.              Animation.RELATIVE_TO_SELF, 0,
  8.              Animation.RELATIVE_TO_SELF, 0,
  9.              Animation.RELATIVE_TO_SELF, 0);
  10.              ta.setDuration(500);
  11.              rv.setAnimation(ta);
  12.          }
  13. }
复制代码

上面的代码第一句是禁用默认动画,然后就获取rv,创建一个滑动的动画,使页面从左往右滑入,动画时长500毫秒,然后为rv设置动画。

你无需为rv启动动画,因为当rv被加载到activity中的时候,rv的动画就会被执行了。

6、如何自定义监听

很多开发者想自定义授权页面,但是他们只是知道复制Sample的MyAdapter,却不知道该怎么改,然后发现授权没有回调,于是过来问技术支持,技术支持同时要和好几个人处理问题,因此有时比较奇葩的问题又会转给我。然后我开始的时候也被蒙住,知道我看到他MaAdapter中空荡荡onComplete方法,才恍然大悟。

不要随便复制你看不懂的代码吧!

Sample中有“授权并关注Share SDK官方微博”的需求,因此我添加了这些事件监听,你的应用如果不需要(大部分应用不需要),或者说你的Adapter只是为了删除以下Logo(超过九成的开发者只为这个目的),那就老实新建一个Adapter,然后在onCreate里面调用一句代码删除之就好了,复制粘贴也没有快到什么地方,而且还有大把你看不懂的代码,最后你删删减减,删掉了重要的步骤,授权成功了,你却得不到回调,更别说后续的分享了。

那如果真的需要“授权以后OOXX”呢,比方说“授权以后发一条分享”(好诡异的需求,不是一般是“授权以后关注官方微博”吗),有什么办法呢?那你需要好好阅读Sample里面MyAdapter的代码了。从Share SDK的框架出发,只要编码正确,你可以在任何地方拦截Share SDK的操作回调。MyAdapter就是一个例子,为了演示“授权以后关注官方微博”的功能,它拦截了授权的事件。来看看拦截的代码吧:

  1. private void interceptPlatformActionListener(String platName) {
  2.     Platform plat = ShareSDK.getPlatform(getActivity(), platName);
  3.        // 备份此前设置的事件监听器
  4.        backListener = plat.getPlatformActionListener();
  5.        // 设置新的监听器,实现事件拦截
  6.        plat.setPlatformActionListener(this);
  7. }
复制代码

[/table]backListener是PlatformActionListener,MyAdapter的一个全局变量,它保存的是开发者调用share、authorize或者其他操作前传递进来的回调。保存起来,先不要让它接收到授权结果,然后重新设置一个新的回调——MyAdapter自己。于是将来(网页)授权的结果会优先给MyAdapter,你就可以在MyAdapter的onComplete方法中做各种事情了。看看MyAdapter的做法:

  1. public void onComplete(Platform plat, int action, HashMap<String, Object> res) {
  2.          if (action == Platform.ACTION_FOLLOWING_USER) {
  3.                   // 当作授权以后不做任何事情
  4.                   plat.setPlatformActionListener(backListener);
  5.                   if (backListener != null) {
  6.                           backListener.onComplete(plat, Platform.ACTION_AUTHORIZING, null);
  7.                   }
  8.          }else if (ctvFollow.isChecked()) {
  9.                    // 授权成功,执行关注
  10.                   String account = MainAdapter.SDK_SINAWEIBO_UID;
  11.                   if (TencentWeibo.NAME.equals(plat.getName())) {
  12.                            account = MainAdapter.SDK_TENCENTWEIBO_UID;
  13.                   }
  14.                  plat.followFriend(account);
  15.           }else {
  16.                    // 如果没有标记为“授权并关注”则直接返回
  17.                    plat.setPlatformActionListener(backListener);
  18.                    if (backListener != null) {
  19.                           // 关注成功也只是当作授权成功返回
  20.                            backListener.onComplete(plat, Platform.ACTION_AUTHORIZING, null);
  21.                   }
  22.         }
  23. }
复制代码

这里面过滤两个事件:授权和关注。为什么是两个,因为这个是自定义授权的工具,本来就只有授权的操作会来这里,至于另外的关注,因为我授权结束以后要处理关注。那么我们先看授权的代码(从“else if (ctvFollow.isChecked())”开始)。

首先需要判断用户是否勾选了页面底部的checkbox,这个cb是默认勾选的,但是不能阻止用户取消它。如果勾选了,就代表授权后要关注,因此通过平台名称判断具体应该关注的帐号是什么,执行一个followFriend的操作。这里的代码其实看上去平淡无华,但是如果用户没有勾选,则需要立刻返回授权的结果给外面的代码。但是由于此前我们已经拦截了回调,因此这里需要重新设置回调,设置也很容易,调用原始回调的onComplete方法就行了。

对于已经勾选关注,并且执行了关注的操作,需要等待此关注的结果,错误和取消的回调这里就略过了,你可以看源码,我们看回成功的情况。成功时不能返回“关注成功”,而应该返回“授权成功”,因为关注是附带的操作。和上面说的一样,重置操作回调,然后调用方法给结果,此时需要注意的是外层的onComplete参数action是关注事件,你不能将它传递个backListener,你只能传递Platform.ACTION_AUTHORIZING,表示授权操作。

我觉得大部分有“授权后OOXX”需求的,都是关注而已,但是如果你有其他的需求,那就模仿着改吧。但是如果我强烈建议你不懂就不要复制粘贴!

7、总结

有不少开发者过来当头就问:你们的授权页面可以修改吗——亲,整个页面都可以修改,只是看你懂不懂修改而已。在写这帖子之前我一般建议开发者先看文档,因为文档会告诉你怎么写一个AuthAdapter,然后写代码获取某一个控件,不管是标题栏也还是页面主体,之后运行并断点看看这个控件。在android的ui框架下,从页面中的任意个View出发,你都可以抓到页面的所有View会来,因为View都会保存自己的Children和Parent,从自己的parent一直往上追溯,就可以到达顶层的PhoneView,但是一般不需要到那里(除非你要Activity嵌套——这是一种蹩脚的技术,不要用),但原理都是一样的。不过现在有了这个帖子,有了前面的图片,你应该可以比较清晰知道页面的组成。Share SDK并不会保留任何对这个页面的控制,你可以对它做任何你喜欢的修改,只要别不小心破坏了授权的逻辑就行了。

Rank: 1

主题:
帖子:
积分:
0
发表于 2015-8-15 20:16:22 |
你好,自定义授权界面 我按照上面的方法配置后,还是没起作用,调试时onCreate没有被调用,请问是怎么回事呢

Rank: 1

主题:
帖子:
积分:
0
发表于 2015-8-15 20:17:28 |
你好,我按照上面的方法配置后没起作用,调试发现onCreate没有被调用,请问是怎么回事呢

Rank: 5Rank: 5

主题:
帖子:
积分:
0
发表于 2015-8-17 10:50:06 |
Memory 发表于 2015-8-15 20:17
你好,我按照上面的方法配置后没起作用,调试发现onCreate没有被调用,请问是怎么回事呢 ...

您好,您的AndroidManifest的注册路径对了吗?是不是您修改授权页面那个类?您可以联系我们:4006852216,让我们帮您看看的

Rank: 1

主题:
帖子:
积分:
0
发表于 2016-8-16 19:36:44 |
你好,C:\Users\Administrator\Desktop\1.png  webView中的授权ShareSDK访问你的微博账号,怎么修改啊?

Rank: 1

主题:
帖子:
积分:
0
发表于 2016-8-16 19:37:47 |
你好 WebView中的授权shareSDK访问怎么修改?
1.png

Rank: 5Rank: 5

主题:
帖子:
积分:
0
发表于 2016-8-17 10:15:38 |
CodeBugs 发表于 2016-8-16 19:37
你好 WebView中的授权shareSDK访问怎么修改?

去新浪微博开放平台申请自己的appkey即可,不要使用我们默认的key

Rank: 1

主题:
帖子:
积分:
0
发表于 2016-10-20 19:50:31 |
这是自定义的类:
package com.ccm.ape.adapter;
import cn.sharesdk.framework.authorize.AuthorizeAdapter;
public class MyAuthorizeAdapter extends AuthorizeAdapter {

    public void onCreate() {
        hideShareSDKLogo();
    }
}

这是清单里的配置:
<meta-data android:name="com.ccm.ape.adapter.MyAuthorizeAdapter" android:value="cn.sharesdk.demo.AuthPageAdapter" />

logo没有去掉呢?请问,配置有问题吗?

Rank: 1

主题:
帖子:
积分:
0
发表于 2016-10-20 19:57:26 |
你好!请问,我这样修改了,没效果。
这是自定义的类:
package com.ccm.ape.adapter;

import cn.sharesdk.framework.authorize.AuthorizeAdapter;
public class MyAuthorizeAdapter extends AuthorizeAdapter {

    public void onCreate() {
        hideShareSDKLogo();
    }
}


这是清单配置:
<meta-data android:name="com.ccm.ape.adapter.MyAuthorizeAdapter" android:value="cn.sharesdk.demo.AuthPageAdapter" />

Rank: 5Rank: 5

主题:
帖子:
积分:
0
发表于 2016-10-20 21:12:45 |
kaission 发表于 2016-10-20 19:57
你好!请问,我这样修改了,没效果。
这是自定义的类:
package com.ccm.ape.adapter;

您到res下找到一个图片 名称叫sharesdk_logo 直接删除图片就行了
12下一页
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

技术支持
免费咨询 | 24小时在线
快速回复 返回顶部 返回列表