Android图片海报制作-MaterialDesign使用

来源:互联网 发布:office2007 数据分析 编辑:程序博客网 时间:2024/05/01 23:27

项目地址:https://github.com/coolstar1204/MakePoster

MaterialDesign界面

这个界面控件出来也有好久了,可实际生产项目中,因为兼容老旧手机的需要,不能随便增加这些控件特性。只能是在学习项目中来折腾。在本项目中,主要是使用了com.android.support:appcompat-v7:23.2.0’、 ‘com.android.support:design:23.2.0’、 ‘com.android.support:cardview-v7:23.2.0’三个兼容库。

CardView

这个库就很简单了,只包括如下这十几个类:
CardView
使用起来也很简单:

<android.support.v7.widget.CardView                        xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    app:cardCornerRadius="5dp" //卡片圆角半径    app:cardElevation="3dp"   //卡片阴影高度    app:cardMaxElevation="6dp"    android:layout_margin="2dp"    android:layout_width="match_parent"    android:layout_height="wrap_content">    //...</android.support.v7.widget.CardView>

app:cardElevation 阴影的高度
app:cardMaxElevation 阴影最大高度
app:cardBackgroundColor 卡片的背景色
app:cardCornerRadius 卡片的圆角大小
app:contentPadding 卡片内容于边距的间隔
app:cardUseCompatPadding 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式
app:cardPreventConrerOverlap 在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠

另从http://blog.feng.moe/2015/10/24/something-about-cardview-development/ 处学习到:

在低版本中设置了 CardElevation 之后 CardView 会自动留出空间供阴影显示,而 Lollipop 之后则需要手动设置 Margin 边距来预留空间,导致我在设置 Margin 在 Android 5.x 机器上调试好后,在 Kitkat 机器调试时发现边距非常大,严重地浪费了屏幕控件。
因此,我们需要自定义一个 dimen 作为 CardView 的 Margin 值进行版本适配。

design:23.2.0

这个库主要提供了新界面控件组及系统资源。
Design1Design2

从图中可以看到,里面有本项目用到的CoordinatorLayout及相关辅助类、FloatingActionButton及相关辅助类、Snackbar及对应管理类都出自这个库。
CoordinatorLayout:本控件一般用于界面最底层容器,用于对上面的子View执行超过继承关系的事件管理或叫传递。有几个特定的控件可以使用Behavior方式对非子父控件关系的兄弟控件进行触摸、滚动、位置变化进行监听处理,达到非一条继承链条上的View进行联动变化的能力。
Snackbar:本控件我理解主要是代替Toast的,使用方式也差不多,不过界面更方便定制、同时可以有一个操作按钮自定义,更强大,本例中,就是改变了背景色来区分提示信息的类别。
FloatingActionButton:通过名称也可以知道,这个按钮最大的特色,就是浮动在界面其它控件上,哪怕那个控件不是它的父控件或兄弟控件,都可以通过layout_anchor、layout_anchorGravity属性让其浮动到其上面,同时通过layout_behavior指定行为方式,让其可随锚定控件的移动、缩放等进行关联变化或动画。

appcompat-v7:23.2.0

这个库主要是提供了新的ActionBar、Toolbar标题栏类组,AlertDialog对话框,ThemeUtils,AppCompatButton、AppCompatEditText、AppCompatCheckedTextView一套以AppCompat开关的可视控件组,本例中主要用到了AppCompatCheckedTextView。EditText。

图片海报项目中,使用Material Design界面,按开发流程需要注意以下几点:

  • Theme的设置:为了在新手机上运行过场动画效果,要在values目录和values-v21目录放置theme定义xml,其中values中要放置的是:
 <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">        <item name="colorPrimary">@color/colorPrimary</item>        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <item name="colorAccent">@color/colorAccent</item>        <item name="alertDialogTheme">@style/AppTheme.Dialog.Alert</item>        <item name="android:listDivider">@drawable/divider_bg</item>    </style>

这个的作用是定义了一个叫AppTheme.Base的基本主题,其在本例中是从Theme.AppCompat.Light.NoActionBar继承而来,这个parent一定要指定你最小的应用支持的版本支持的主题。本例中的minSdkVersion 15,所以NoActionBar就可以正常运行在4.0.3及以后版本手机上。上面中还需要注意的最后一个item,是指定RecyclerView中的分割条drawable用的。在自定义分割条类中直接读取的。
同时在values目录和values-v21目录中,都从上面的AppTheme.Base继承定义了AppTheme自定义主题,values中的无扩展设置,但values-v21中的,针对Material Design增加了一些设置属性,有需要的地方,就需要自己设置修改了:

<style name="AppTheme" parent="AppTheme.Base">        <item name="android:windowContentTransitions">true</item>        <item name="android:windowAllowEnterTransitionOverlap">true</item>        <item name="android:windowAllowReturnTransitionOverlap">true</item>        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>        <item name="android:windowNoTitle">true</item>        <item name="windowActionBar">false</item>    </style>

其中各item意义如下:
– android:windowContentTransitions:开启转场动画效果(炫酷转换就要设置为true)
– android:windowSharedElementEnterTransition、android:windowSharedElementExitTransition:指定共享元素的转场动画效果,这里使用了系统定义的move动画。
– android:windowAllowEnterTransitionOverlap、android:windowAllowReturnTransitionOverlap:这二个是指示是否过渡动画在进入和退出的二个窗体中重叠执行。(貌似我使用的move动画不受这二个参数影响,true和false都差不多)

  • 在二个Activity的界面布局中,指定二个View使用相同的android:transitionName属性,在本程序中,MainActivity界面动画打开PosterActivity界面,所以我在MainActivity的界面中,把android:transitionName指定到主界面RecyclerView中的ViewHolder用的界面布局xml中显示小图的ImageView控件中,也就是主界面有多图时,会有多图都有这个属性设置,而在PosterActivity中,我把这个transitionName属性指定给了最外罢的容器CoordinatorLayout控件,但显示图的控件是其子控件,自定义的TextDrawer,同样达到了在MainAcitvity中的小图进行放大动画转场到PosterActivity的大图效果。证明不需要有相同android:transitionName设置的控件必须是都是加载相同图片的控件,而且我在开发中,还发现我如果把android:transitionName属性指定给TextDrawer后,可能 是因为自定义绘制原因,在动画过程中,多次触发onSizeChanged事件,但界面却不重绘,最终转场后,图片还是原来主界面大小显示状态,要强制刷新一下才放大显示的问题,换成标准控件ImageView就没问题。后来是把android:transitionName属性移到CoordinatorLayout后,才能正常缩放动画转场。

  • 使用ActivityOptionsCompat,在进行Activity的跳转时,使用如下代码,才能支持转场动画 :

private void openPosterActivity(PictureInfo item,View v) {        ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this,v,getString(R.string.main_trans_imgname));        Bundle bundle = optionsCompat.toBundle();        Intent intent = new Intent(this, PosterActivity.class);        intent.putExtra("PictureInfo",item);        ActivityCompat.startActivity(this,intent,bundle);    }

其中main_trans_imgname就是指定的android:transitionName,v就是当前点击的RecyclerView的项布局中指定了transitonName的ImageView控件。我理解这里的v一定要传有transitonName指定的控件。

—————————————–至此、转换动画几处设置结束————————————-

  • RecyclerView的使用
    这个控件是大家比较熟悉的了。只需要按那几个步骤都能很快使用上,这里简单再过一下:
    如下面代码:
    1.设置LayoutManager,有默认的三种,线性(支持竖向与横向),表格,瀑布流
    2.创建项布局xml及对应的ViewHolder(RecyclerView.ViewHolder的子类),这里要把xml中的控件全部转为变量,用于在onBindViewHolder事件中关联数据。
    3.创建泛类型为上面自己写的ViewHolder的Adapter(RecyclerView.Adapter)子类,此类主要就三个方法,一个是创建ViewHolder的onCreateViewHolder,另一个关联数据的onBindViewHolder,还有一个就是getItemCount,用于返回项数量,当然最强大的一点是,它还有一个可以控制不同position的ViewHolder类型的能力getItemViewType,这样可以很方便的实现不同项布局的混合排列,而且你不用关系复用时ViewHolder的类型不同问题。
    4.设置默认项动画,在项增加或删除时展现动画效果(这里要注意是特定的增加notifyItemInserted和删除notifyItemRemoved才会有动画)
    5.可选设置项间隔,这个比较麻烦,需要自己实现一个子类(对应不同的布局管理器要实现不同的间隔类),本例中是使用的GridLayoutManager,所以这里就借用了鸿祥大神的演示类,这个类因为是从系统的listDivider属性读取分割用drawable,所以必须要先到theme中声明一下这个属性所指定的drawable,我这里使用了一个shapeDrawable用来呈现5dp的透明分割区域。在RecyclerView中没办法直接指定listDivider这点比较郁闷,如果不同界面分割符不一样,可能这种实现就要修改。
 listView = (RecyclerView)findViewById(R.id.main_recylerView); //listView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));//listView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));GridLayoutManager gridLayoutMgr = new GridLayoutManager(this,2);gridLayoutMgr.setOrientation(GridLayoutManager.VERTICAL);listView.setLayoutManager(new GridLayoutManager(this,2));DividerGridItemDecoration decoration = new DividerGridItemDecoration(this);listView.addItemDecoration(decoration);listView.setItemAnimator(new DefaultItemAnimator());
  • CoordinatorLayout.Behavior的自定义使用
    在默认的Material Design中,只要你放置了CoordinatorLayout和FloatingActionButton,FloatingActionButton类在定义时,就声明了一个默认的Behavior类,这样在有Snackbar出现且FloatingActionButton在下面锚定时,就会自动向上升起防止被遮挡,在FloatingActionButton与AppBarLayout、CollapsingToolbarLayout在上面一起配合时,FloatingActionButton就有默认的向上滚蛋一段距离后缩放消失效果。而这一切效果的本质,就是Behavior的能力。在本例中,因为在编辑界面有一个下边栏有向上升起的动画,所以实现了一个自定义的Behavior,让FloatingActionButton随我们自定义的View布局一起上升或下降,不再跟随SnackBar联动。
public class DependentBehavior extends CoordinatorLayout.Behavior<View> {    private float initChildTop;    public DependentBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {        return dependency instanceof RelativeLayout;  //依赖相对布局的类    }    @Override    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {        if(dependency instanceof RelativeLayout){            if(initChildTop==0){                initChildTop = child.getTop();            }            float totalTransY = ScreenUtility.dip2px(160);            float rotateRank = (child.getTop()-initChildTop)/totalTransY*180;            child.setRotation(rotateRank);            ViewCompat.setTranslationY(child,-child.getHeight()/3);  //这里的除3是根据图标大小计算,但为什么只设置一个固定值就能改变transY,还不知道原因?            return true;        }        return super.onDependentViewChanged(parent, child, dependency);    }    //...去掉空实现的函数 }
  • SnackBar的使用
    此类直接使用和Toast一样简单,这里修改的一点是按网上一人博客(抱歉记不得网址)的方式,把
    SnackBar的背景色和内容类别进行关联。可以达到更好的提示效果。
 public void showMessage(String msg) {        Snackbar snackbar = Snackbar.make(mDrawer,msg,Snackbar.LENGTH_SHORT);        ColoredSnackbar.info(snackbar).show();    }
public class ColoredSnackbar {    private static final int red = 0xfff44336;    private static final int green = 0xff4caf50;    private static final int blue = 0xff2195f3;    private static final int orange = 0xffffc107;    private static View getSnackBarLayout(Snackbar snackbar) {        if (snackbar != null) {            return snackbar.getView();        }        return null;    }    private static Snackbar colorSnackBar(Snackbar snackbar, int colorId) {        View snackBarView = getSnackBarLayout(snackbar);        if (snackBarView != null) {            snackBarView.setBackgroundColor(colorId);        }        return snackbar;    }    public static Snackbar info(Snackbar snackbar) {        return colorSnackBar(snackbar, blue);    }    public static Snackbar warning(Snackbar snackbar) {        return colorSnackBar(snackbar, orange);    }    public static Snackbar alert(Snackbar snackbar) {        return colorSnackBar(snackbar, red);    }    public static Snackbar confirm(Snackbar snackbar) {        return colorSnackBar(snackbar, green);    }}
0 0
原创粉丝点击