Всем привет. Не писал сто лет, времени небыло вообще. Решил написать пару статей по простым задачам которые я встречал за этот год который я не писал. Уже забыл как это делается, по этому буду учиться с начала.
В общем задача у нас такая — мы хотим создать вьюху которую родные андроидовские элементы не позволяют создать, в нашем случае я выбрал простой пример что бы поменьше кода писать, чисто пример, если будет интересней — то напишу статью с более сложной вьюхой. В общем у нас будут табы, которые можно плодить в приложении множеством раз, с разными параметрами и функциями, можно кастомизировать текст внутри вьюхи и прятать например. В общем места для игры фантазии море.
Для того что бы нам сделать такое. Нам нужно создать вьюху которая будет выглядеть так мы хотим что бы оно выглядело. Я захотел сделать ее такой:
У нас это будет просто три таба по нажатию на которые мы будем переходить на разные фрагменты. Дальше если захотите что то поменять в этих табах вам достаточно добавить нужный элемент на таб и прописать его функции в классе который будет реализовывать функции этой вьюхи.
XML данной вьюхи будет выглядеть так:
view_top_tabs.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:text="@string/opinion.last.week"
android:background="@drawable/selected_rounded_button"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_weight="0.1"
android:layout_height="40dp"
android:id="@+id/lastWeek" />
<Button
android:text="@string/opinion.last.month"
android:layout_width="match_parent"
android:layout_height="40dp"
android:id="@+id/lastMonth"
android:background="@drawable/unselected_tranding_rounded_button"
android:textColor="@color/colorPrimary"
android:layout_weight="0.1"
android:layout_marginLeft="10dp" />
<Button
android:text="@string/opinion.all.time"
android:layout_width="match_parent"
android:layout_height="40dp"
android:id="@+id/allTime"
android:background="@drawable/unselected_tranding_rounded_button"
android:textColor="@color/colorPrimary"
android:layout_weight="0.1"
android:layout_marginLeft="10dp" />
</LinearLayout>
</LinearLayout>
Тут собственно мы вставили 3 кнопки, по нажатию на которые мы меняем их стиль. Далее нам нужно создать класс который будет наследоваться от LinearLayout, и дальше начать имплементить функции для кнопок которые мы добавили в XML.
Так же тут не хватает нам нескольких цветов и пары drawable файлов, в нашем случае цвета такие:
color.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="white">#fff</color>
</resources>
Дальше наши drawable файлы, первый у нас скругленный но пустой внутри для отображения активного таба.
selected_rounded_button.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" android:padding="10dp">
<solid android:color="@color/colorPrimaryDark"/>
<corners
android:bottomRightRadius="30dp"
android:bottomLeftRadius="30dp"
android:topLeftRadius="30dp"
android:topRightRadius="30dp"/>
</shape>
Второй же для того что бы отображать табы который на данный момент не активные, что бы не путать пользователя.
unselected_tranding_rounded_button.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" android:padding="10dp">
<solid android:color="@color/white"/>
<corners
android:bottomRightRadius="30dp"
android:bottomLeftRadius="30dp"
android:topLeftRadius="30dp"
android:topRightRadius="30dp"/>
<stroke android:width="2dp"
android:color="@color/colorPrimary"/>
</shape>
Дальше привожу код который описывает работу XML файла, все комментарии есть в коде.
TopTabsView.java
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import com.project.customviewproject.R;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
public class TopTabsView extends LinearLayout implements View.OnClickListener {
public static final int LAST_WEEK = 0;
public static final int LAST_MONTH = 1;
public static final int ALL_TIME = 2;
@BindView(R.id.lastWeek)
Button lastWeek;
@BindView(R.id.lastMonth)
Button lastMonth;
@BindView(R.id.allTime)
Button allTime;
@BindColor(R.color.white)
int whiteColor;
@BindColor(R.color.colorPrimary)
int blueColor;
private OnTopTabsViewClickListener onTopTabsViewClickListener;
private int currentTab;
public TopTabsView(Context context) {
super(context);
init(context);
}
public TopTabsView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
setParams(context, attrs);
}
public TopTabsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
setParams(context, attrs);
}
private void setParams(Context context, AttributeSet attrs) {
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.TopTabsComponent);
int tabId = arr.getInt(R.styleable.TopTabsComponent_tabId, LAST_WEEK);
setActiveTab(tabId);
arr.recycle();
}
private void init(Context context) {
inflate(context, R.layout.view_top_tabs, this);
setOrientation(VERTICAL);
ButterKnife.bind(this);
setUp();
}
private void setUp() {
lastWeek.setOnClickListener(this);
lastMonth.setOnClickListener(this);
allTime.setOnClickListener(this);
}
public void setActiveTab(int tabId) {
currentTab = tabId;
switch (tabId) {
case LAST_WEEK:
lastWeek.setBackgroundResource(R.drawable.selected_rounded_button);
lastWeek.setTextColor(whiteColor);
lastMonth.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
lastMonth.setTextColor(blueColor);
allTime.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
allTime.setTextColor(blueColor);
break;
case LAST_MONTH:
lastWeek.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
lastWeek.setTextColor(blueColor);
lastMonth.setBackgroundResource(R.drawable.selected_rounded_button);
lastMonth.setTextColor(whiteColor);
allTime.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
allTime.setTextColor(blueColor);
break;
case ALL_TIME:
lastWeek.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
lastWeek.setTextColor(blueColor);
lastMonth.setBackgroundResource(R.drawable.unselected_tranding_rounded_button);
lastMonth.setTextColor(blueColor);
allTime.setBackgroundResource(R.drawable.selected_rounded_button);
allTime.setTextColor(whiteColor);
break;
}
}
public int getCurrentTab() {
return currentTab;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.lastWeek:
setActiveTab(LAST_WEEK);
onTopTabsViewClickListener.onTopTabViewClick(LAST_WEEK);
break;
case R.id.lastMonth:
setActiveTab(LAST_MONTH);
onTopTabsViewClickListener.onTopTabViewClick(LAST_MONTH);
break;
case R.id.allTime:
setActiveTab(ALL_TIME);
onTopTabsViewClickListener.onTopTabViewClick(ALL_TIME);
break;
}
}
public void setOnTopTabsViewClickListener(OnTopTabsViewClickListener onTopSubTabsViewClickListener) {
this.onTopTabsViewClickListener = onTopSubTabsViewClickListener;
}
public interface OnTopTabsViewClickListener {
int onTopTabViewClick(int tabId);
}
}
Так же нам не хватает файла который описывает константы из attrs файла.
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TopTabsComponent">
<attr name="tabId" format="integer">
<enum name="lastWeek" value="0" />
<enum name="lastMonth" value="1" />
<enum name="allTime" value="2" />
</attr>
</declare-styleable>
</resources>
Теперь у нас есть кастомная вьюха которая умеет переключать табы, умеет их красить и возвращать он клик в активити или фрагмент в которую мы это засетим. По этому продолжим делать красоту. У нас есть MainActivity которая будет главным экраном приложения в котором будут эти табы, и в ней у нас будет происходить переключение фрагментов. В общем вот наш файл разметки для MainActivity.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.project.customviewproject.view.TopTabsView
android:id="@+id/topBarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:tabId="lastWeek"></com.project.customviewproject.view.TopTabsView>
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp">
</FrameLayout>
</LinearLayout>
Интересный параметер app:tabId. Он у нас означает какой таб будет отображаться по умолчанию его мы задаем в XML если хотим, или можем его задать из активити, если очень хочется. Но как по мне эстетичней все таки через XML.
Теперь что же мы делаем в нашей MainActivity? Мы имплементим наш кастом таб вью и переопределяем наш колбек который возвращает кликнутую кнопку, и отображает фрагмент который нам нужен.
MainActivity.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import com.project.customviewproject.ui.AllTimeFragment;
import com.project.customviewproject.ui.LastMonthFragment;
import com.project.customviewproject.ui.LastWeekFragment;
import com.project.customviewproject.view.TopTabsView;
import butterknife.BindView;
import butterknife.ButterKnife;
import static com.project.customviewproject.view.TopTabsView.ALL_TIME;
import static com.project.customviewproject.view.TopTabsView.LAST_MONTH;
import static com.project.customviewproject.view.TopTabsView.LAST_WEEK;
public class MainActivity extends AppCompatActivity implements TopTabsView.OnTopTabsViewClickListener {
@BindView(R.id.topBarView)
TopTabsView topTabsView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
topTabsView.setOnTopTabsViewClickListener(this);
onTopTabViewClick(topTabsView.getCurrentTab());
}
@Override
public int onTopTabViewClick(int tabId) {
Fragment fragment = null;
switch (tabId) {
case LAST_WEEK:
fragment = new LastWeekFragment();
break;
case LAST_MONTH:
fragment = new LastMonthFragment();
break;
case ALL_TIME:
fragment = new AllTimeFragment();
break;
}
setupFragment(fragment);
return LAST_WEEK;
}
private void setupFragment(Fragment fragment) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, fragment)
.commit();
}
}
Так же нам нужно создать три фрагмента с разными надписями, ну или там с разными данными, списками или чем-то еще… Я создал три разные вьюхи просто с разными текствью.
fragment_last_week
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
android:background="@color/white">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/opinion.last.week"
android:textSize="24sp" />
</LinearLayout>
LastWeekFragment.java
public class LastWeekFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_last_week, container, false);
ButterKnife.bind(this, view);
return view;
}
}
fragment_last_month
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
android:background="@color/white">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/opinion.last.month"
android:textSize="24sp" />
</LinearLayout>
LastMonthFragment.java
public class LastMonthFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_last_month, container, false);
ButterKnife.bind(this, view);
return view;
}
}
fragment_all_time
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
android:background="@color/white">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/opinion.all.time"
android:textSize="24sp" />
</LinearLayout>
AllTimeFragment.java
public class AllTimeFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_all_time, container, false);
ButterKnife.bind(this, view);
return view;
}
}
Результатом у нас будет активити с тремя табами, по клику на которые мы будем переходить по фрагментам.
Исходники:
Комментариев нет:
Отправить комментарий